Storing previous state with useRef

DEMO
The useRef hook gives us a mutable ref object that lasts the full lifetime of the component but never causes a rerender. In this use case, we store the previous pokemon state/s without having to rerender.
Pokedex.jsx

const StorePreviousStateUseRef = () => {
  const [currPokemon, setCurrPokemon] = useState(null);
  const pokeHistory = useRef([]);

  const fetchPokemon = useCallback(
    async (id) => {
      const num = id || Math.floor(Math.random() * 300) + 1;
      const resp = await fetch(`https://pokeapi.co/api/v2/pokemon/${num}`);
      const data = await resp.json();
      setCurrPokemon({
        img: data.sprites.other["official-artwork"].front_default,
        name: data.name,
      });
    },
    []
  );

  useEffect(() => {
    fetchPokemon(151);
  }, []);

  useEffect(() => {
    // add the current pokemon to array stored in the ref
    pokeHistory.current.unshift(currPokemon);
    // only allow 3 items in this 'history' array
    if (pokeHistory.current.length > 3) {
      pokeHistory.current.pop();
    }
    // note that the ref object will include the current pokemon
    // but since it doesn't cause rerender, it won't show up
  }, [currPokemon]);

  return (
    <>
      <MainPokemon>
        {currPokemon && (
          <>
            <img src={currPokemon.img} />
            <PokemonName>
              {currPokemon.name.charAt(0).toUpperCase() +
                currPokemon.name.slice(1)}
            </PokemonName>
          </>
        )}
      </MainPokemon>
      <PokeballBtn onClick={() => fetchPokemon()}>
        <img src={pokeBall} />
      </PokeballBtn>
      <History>
        {[...Array(3).keys()].map((key) => (
          <MiniPokemon>
            <img src={pokeHistory.current[key]?.img} />
          </MiniPokemon>
        ))}
      </History>
    </>
  );
};

Note: Code snippets do not include styling details unless they are the focus of the exercise.

Copyright © 2022 Explore React