Pokemon Book
is a Pokémon type and attribute details viewing tool that helps users quickly understand Pokémon's attribute restraint relationships, skill effects, and related data.
This is a documentation lists all the problems or noticeable thing during the app development.
Time difference of asynchronous data loading
How to properly encapsulate Json data
Encapsulate nested JSON data structure
Intercept part of the data in the URL
The list data rendered by forEach is undefined
This is a relatively troublesome problem because it involves the time difference of data rendering. For example, when I render the Index
page, the list has not been rendered yet, and we access the unrendered Pokémon unit to get the type
, which results in an error
(The problem encountered is caused by the time difference between asynchronous loading and rendering. When the data has not been fully loaded, the code tries to access undefined properties, resulting in a compilation error "Object is possibly 'undefined'.")
We must ensure the order of asynchronous operations. Use Promise
or async/await
to ensure that all data is loaded before performing subsequent operations. For example, Promise.all
can be used to handle multiple asynchronous calls.
The general logic is as follows:
const list = await source.getPokemonList();
this.pokeList = list;
// Get the type of each Pokémon and store it in typeList
const infoPromises = this.pokeList.map((item, index) =>
source.getPokemonType(index).then((types) => {
this.typeList[index] = types; // Store type array into two-dimensional array typeList
})
);
await Promise.all(infoPromises); // Wait for all asynchronous tasks to complete
Unable to parse the requested Http Get
JSON data when writing the DataSource
data source.
We need to design model
or interface
reasonably to make requests, and further split according to the model structure of the request
async getTypeDetail(url: string): Promise<DamageRelations> {
return new Promise<DamageRelations>((resolve, reject) => {
let httpRequest = http.createHttp()
httpRequest.request(`${url}`, (err, data) => {
if (!err) {
try {
// parse requested JSON data and receive with designed model
let responseData: PokemonTypeData = JSON.parse(data.result as string)
const res: DamageRelations = responseData.damage_relations
resolve(res)
} catch (parseErr) {
console.error('JSON Parse Error', parseErr);
reject(err);
}
} else {
console.error('HTTP Error:', err);
reject(err);
}
})
})
}
Taking the above example, after we call http.createHttp()
, we need a suitable data type to receive the parsed data. PokemonTypeData
in the above example is
In addition, each split structure must be reasonably encapsulated before use
To solve this problem, a recursive function is used
this.evolutionSpecies = this.extractSpeciesNames(this.pokeEvolution.chain as EvolutionChain)
// Recursive method to extract species names
extractSpeciesNames(chain: EvolutionChain, result: Species[] = []): Species[] {
result.push({
name: chain.species.name,
url: chain.species.url
});
chain.evolves_to.forEach((nextChain) => {
this.extractSpeciesNames(nextChain, result);
});
return result;
}
In some special cases, we need to intercept a part of a string in a specific format. In this example, we need to intercept the last number of url
function extractLastNumber(url: string): number {
const parts = url.split('/').filter((part) => part !== ''); // Split by slash and filter out empty strings
const lastPart = parts[parts.length - 1]; // Get the last part
return parseInt(lastPart, 10); // Convert to a number and back
}
Directly accessing asynchronously updated values inside forEach may result in inconsistent data state. You can use a for loop to process them one by one instead.
if (Array.isArray(this.effectEntry))
for(const item of this.effectEntry){
if (item.language?.name === 'en') {
this.effectInfo.language = item.language;
this.effectInfo.short_effect = item.short_effect;
break;
}
}