Reputation: 127
I'm sorry that this question has been asked in a similar fashion. I've read through a lot of similar threads but just don't know enough to apply it to my little project. I'm very new to React so I would appreciate any help!
Getting to it, I'm making a pokemon game where someone can hit click buttons to filter down a JSON list of pokemon. They can go by type,weaknessess,etc.
But I'm a little confused in keeping a 'global array' if that's the right word. It may be something I don't understand with React's useState.
Here's my code
import React, { useState, useEffect } from "react";
import "./App.css";
import PokemonLibrary from "./data/PokemonList.json";
export default function App() {
const [pokemonData, setPokemonData] = React.useState(PokemonLibrary.pokemon);
const pokeListCopy = PokemonLibrary.pokemon;
const filterTypeOne = () => { //filter type
const myFilteredPoke = pokeListCopy.filter((pokeType) => {
return pokeType.type.includes("Grass");
});
console.log(myFilteredPoke); // shows array of objects of left over pokemon
setPokemonData(myFilteredPoke);
};
const filterWeakness = () => { //filter weakness
const myFilteredPoke = pokeListCopy.filter((pokeType) => {
return pokeType.weaknesses.includes("Ice");
});
setPokemonData(myFilteredPoke);
};
return (
<div className="App">
<h1>Pokemon Selector!</h1>
<div>
<button onClick={filterTypeOne}>Filter Grass</button>
<button onClick={filterWeakness}>Weak to Ice</button>
</div>
{pokemonData &&
pokemonData.map((poke) => (
<p key={poke.id}>
#{poke.num} | {poke.name} | {poke.type[0]} {poke.type[1]}
<img src={poke.img} alt="Pokemon Images"></img>
</p>
))}
</div>
);
}
My question is, how do I keep a consistent array for these two functions (and more) to pull the same data from? I'd like it to be able to be filtered in either order. But currently, these filter separate arrays. I've played with it a lot using normal JavaScript, but I can't quite figure this out.
I hope that was enough information. Please let me know if this didn't make sense! I'd appreciate any guidance. Thank you.
Upvotes: 3
Views: 578
Reputation: 6055
You are facing this problem because you try to set the state of the list in an "imperative" manner, but React is meant to be used more "declarative". That means, what you try here is like:
but how you should use React is:
That might sound like the same, but there is a subtle difference. React is good in changing a state dependent on some other state. You might say "but that's what I'm trying to do, changing the state of the list", but then you have tell the full story
This becomes quite complicated, especially comparing contents of lists and components.
There are different solutions to your problem, but what you should do is basically something like:
e.g.:
const [pokemonData, setPokemonData] = React.useState(PokemonLibrary.pokemon);
const [listState, setListState] = React.useState({ type: '', weekness: '' });
useEffect(() => {
let newList = pokemonData;
if( listState.type === 'Grass' ){
newList = newList.filter( ... );
}
if( listState.weekness === 'Ice' ){
newList = newList.filter( ... );
}
setPokemonData(newList);
}, listState );
return (
<div>
<button onClick={()=>{ setListState({ ...listState, type: 'Grass' }) }}>Filter Grass</button>
{ pokemonData.map( (poke) => ... ) }
</div>
);
(This code is not very elegant and would not even work, and should only illustrate the idea. From here on there are several ways how to implement the filtering mechanism)
Upvotes: 1