3

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.

2
  • 1
    You can follow this thread for your approach: stackoverflow.com/questions/48834275/… Commented Oct 1, 2021 at 5:54
  • Thank you for your response! So I should put my filter functions into an array and have a different function that goes through these functions and applies these two filters on my array? I'm still trying to play with it. I guess my JS isn't as good as I hoped. Can I ask where would I put the function to update React? I've been using setPokemonData(myFilteredPoke); but I don't quite know if that's the best way to do it. Commented Oct 2, 2021 at 3:26

1 Answer 1

1

Problem

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:

  • "if I click the button, change the list to contain the items that contain 'Grass'",

but how you should use React is:

  • "if I click the button, then the state of my component should be that the list only contains items with 'grass'"

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

  • "if I click the button, and the list is not filtered already, and maybe contains the items X, then change the list to contain the items that contain 'Grass', unless ..."

This becomes quite complicated, especially comparing contents of lists and components.

Solution

There are different solutions to your problem, but what you should do is basically something like:

  • set the component state to describe what you want
  • have other parts of your program (and React) take care to give you a the list dependent on this description

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)

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you very much for your detailed answer! I have a lot of trouble with state as you can tell. Unsure of when to use it. I'm following some online courses to help learn this stuff but I wanted to see if I could solve this problem with what I know now. I'll read and re-read what you wrote and see what I can do.
I just found a nice, short example: Filter array of objects with multiple conditions. With this approach you can modify the 'filters' state instead of the 'pokemonData' state, and build the new 'pokemonData' to be displayed inside a useEffect, as in my example (I called the filters 'listState' there). There are other possible approaches.
Thank you so much for coming back and adding more information! I will definitely take a look at that example and play with it first before incorporating it into react. I'll do my best to get it working.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.