Change Redux code style by move all slice initialization process into pokedexSlice, Component are majorly for presentation

develop
Jason Zhu 2023-04-06 23:57:05 +10:00
parent fa4fb04efb
commit 83ae2f34d7
4 changed files with 70 additions and 82 deletions

View File

@ -4,33 +4,10 @@ import {
setSelectedRegion,
setSelectedType,
setSelectedSort,
setRegionPokemonIdsList,
} from 'features/Pokedex/pokedexSlice';
import { RegionPokemonRange } from 'features/Pokedex/types/slice';
import { useAppDispatch, useAppSelector } from 'app/hooks';
const useGetSortOptions = () => {
const sortOptions = [
{ name: 'ID', value: 'id' },
{ name: 'Name', value: 'name' },
];
return { data: sortOptions };
};
export const useGetRegionPokemons = () => {
const data: RegionPokemonRange[] = [
{ region: 'kanto', startId: 1, endId: 151 },
{ region: 'johto', startId: 152, endId: 251 },
{ region: 'hoenn', startId: 252, endId: 386 },
{ region: 'sinnoh', startId: 387, endId: 493 },
{ region: 'unova', startId: 494, endId: 649 },
{ region: 'kalos', startId: 650, endId: 721 },
{ region: 'alola', startId: 722, endId: 809 },
{ region: 'galar', startId: 810, endId: 898 },
];
return { data: data };
};
export const createRegionPokemonListOptionElements = (
data: RegionPokemonRange[],
) => {
@ -49,54 +26,20 @@ export const createRegionPokemonListOptionElements = (
const Filters = () => {
const dispatch = useAppDispatch();
const selectedRegion = useAppSelector(state => state.pokedex.selectedRegion);
const selectedType = useAppSelector(state => state.pokedex.selectedType);
const selectedSort = useAppSelector(state => state.pokedex.selectedSort);
const handleRegionChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
dispatch(setSelectedRegion(event.target.value));
};
const handleTypeChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
dispatch(setSelectedType(event.target.value));
};
const handleSortChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
dispatch(setSelectedSort(event.target.value));
};
const regionPokemonList = useAppSelector(
state => state.pokedex.regionPokemonIdsList,
);
const sortOptions = useAppSelector(state => state.pokedex.sortList);
const { data: typesData, isLoading: typesLoading } = useGetTypeListQuery();
const { data: sortOptions } = useGetSortOptions();
const { data: regionPokemonListData } = useGetRegionPokemons();
// Action when loading the component
useEffect(() => {
dispatch(setRegionPokemonIdsList(regionPokemonListData));
const optionElements =
createRegionPokemonListOptionElements(regionPokemonList);
const initailRegion = Object.keys(regionPokemonListData)[0];
if (initailRegion) {
const initialEvent = {
target: { value: initailRegion },
} as React.ChangeEvent<HTMLSelectElement>;
handleRegionChange(initialEvent);
}
if (sortOptions && sortOptions.length > 0) {
const initialSortEvent = {
target: { value: sortOptions[0].value },
} as React.ChangeEvent<HTMLSelectElement>;
handleSortChange(initialSortEvent);
}
}, []);
// Send the first type as the default selected type
useEffect(() => {
if (typesData && typesData.results.length > 0) {
const initialTypeEvent = {
target: { value: typesData.results[0].name },
} as React.ChangeEvent<HTMLSelectElement>;
handleTypeChange(initialTypeEvent);
}
}, [typesData]);
const optionElements = createRegionPokemonListOptionElements(
regionPokemonListData,
);
return (
<>
<div className="filter__container">
@ -105,8 +48,8 @@ const Filters = () => {
<div>REGION</div>
<select
name="regionSelect"
onChange={handleRegionChange}
value={Object.keys(regionPokemonListData)[0]}
onChange={e => dispatch(setSelectedRegion(e.target.value))}
value={selectedRegion}
>
{optionElements}
</select>
@ -115,7 +58,11 @@ const Filters = () => {
<div className="filter__items">
<div>
<div>TYPE</div>
<select name="regionSelect" onChange={handleTypeChange}>
<select
name="regionSelect"
onChange={e => dispatch(setSelectedType(e.target.value))}
value={selectedType}
>
{typesLoading ? (
<option>Loading...</option>
) : (
@ -134,7 +81,8 @@ const Filters = () => {
<select
name="sortSelect"
disabled={typesLoading}
onChange={handleSortChange}
onChange={e => dispatch(setSelectedSort(e.target.value))}
value={selectedSort}
>
{sortOptions.map(option => (
<option key={option.value} value={option.value}>

View File

@ -3,25 +3,29 @@ import Pokemon from './Pokemon';
import Filters from './Filters';
import Loading from 'components/Loading';
import charizard from 'features/Pokedex/Pokemon/assets/stories/charizard.svg';
import { useAppSelector } from 'app/hooks';
const Pokedex = () => {
const isFetchingRegionPokemonList = useAppSelector(
state => state.pokedex.fetchingRegionPokemonList,
const isLoadingPokemons = useAppSelector(
state => state.pokedex.isLoadingPokemons,
);
const pokemonList = useAppSelector(state => state.pokedex.pokemonList);
return (
<>
<Filters />
{isFetchingRegionPokemonList ? (
{isLoadingPokemons ? (
<Loading />
) : (
<Pokemon
name={'Charizard'}
number={6}
image={charizard}
types={['fire', 'flying']}
/>
pokemonList.map(pokemon => (
<Pokemon
key={pokemon.id}
name={pokemon.name}
number={pokemon.id}
image={pokemon.sprites.other.dream_world.front_default}
types={pokemon.types.map(type => type.type.name)}
/>
))
)}
</>
);

View File

@ -6,12 +6,31 @@ import { PokedexState, RegionPokemonRange } from 'features/Pokedex/types/slice';
import { getStartAndEndIdsForRegion } from './utils';
import { PokemonResponseData } from './types/api';
import { pokedexApi } from './pokedexApi';
const data: RegionPokemonRange[] = [
{ region: 'kanto', startId: 1, endId: 151 },
{ region: 'johto', startId: 152, endId: 251 },
{ region: 'hoenn', startId: 252, endId: 386 },
{ region: 'sinnoh', startId: 387, endId: 493 },
{ region: 'unova', startId: 494, endId: 649 },
{ region: 'kalos', startId: 650, endId: 721 },
{ region: 'alola', startId: 722, endId: 809 },
{ region: 'galar', startId: 810, endId: 898 },
];
const sortOptions = [
{ name: 'ID', value: 'id' },
{ name: 'Name', value: 'name' },
];
pokedexApi.endpoints.getTypeList.initiate();
const initialState: PokedexState = {
selectedRegion: '',
regionPokemonIdsList: [],
regionPokemonIdsList: data,
selectedType: '',
typeList: [],
selectedSort: '',
sortList: sortOptions,
isLoadingPokemons: true,
pokemonList: [],
};
@ -41,6 +60,22 @@ export const pokedexSlice: Slice<PokedexState> = createSlice({
setPokemonList: (state, action: PayloadAction<PokemonResponseData[]>) => {
state.pokemonList = action.payload;
},
setTypeList: (state, action: PayloadAction<string[]>) => {
state.typeList = action.payload;
},
},
extraReducers: builder => {
builder.addMatcher(
pokedexApi.endpoints.getTypeList.matchFulfilled,
(state, action) => {
if (action.payload && action.payload.results.length > 0) {
const regionListResults = action.payload.results;
state.typeList = regionListResults.map(region => region.name);
state.selectedType = action.payload.results[0].name;
}
},
);
},
});
@ -48,7 +83,6 @@ export const {
setSelectedRegion,
setSelectedType,
setSelectedSort,
setRegionPokemonIdsList,
setIsLoadingPokemons,
setPokemonList,
} = pokedexSlice.actions;

View File

@ -4,7 +4,9 @@ export type PokedexState = {
selectedRegion: string;
regionPokemonIdsList: RegionPokemonRange[];
selectedType: string;
typeList: string[];
selectedSort: string;
sortList: { name: string; value: string }[];
isLoadingPokemons: boolean;
pokemonList: PokemonResponseData[];
};