Why clicking Back to the list sends me pack to front page? Using hooks

Viewed 29

I'm setting a value when you click on Back to List. As per logic it should not go back to the 1st page which appears when I load the browser. I specified a value

<a href="#" onClick={() => setPokemon(pokemon.name)}>

If I wanted to go back to the list page I should have passed null like this.
<a href="#" onClick={() => setPokemon(null)}>

Here is the full code.

import "./styles.css";
import { QueryClient, QueryClientProvider, useQuery } from "react-query";
import axios from "axios";
import { useState } from "react";

const queryClient = new QueryClient();

function App() {
  // useEffect(() => {
  //   queryClient.clear();
  // }, []);

  const [pokemon, setPokemon] = useState(null);
  return (
    <QueryClientProvider client={queryClient}>
      <div className="App">
        {pokemon ? (
          <Pokemon pokemon={pokemon} setPokemon={setPokemon} />
        ) : (
          <PokemonList setPokemon={setPokemon} />
        )}
      </div>
    </QueryClientProvider>
  );
}

export default App;

function usePokemonList() {
  return useQuery("pokemon", async () => {
    const { data } = await axios.get(
      "https://pokeapi.co/api/v2/pokemon?offset=0&limit=50"
    );
    return data.results;
  });
}

function usePokemon(name) {
  return useQuery(["pokemon", name], async () => {
    const { data } = await axios.get(
      `https://pokeapi.co/api/v2/pokemon/${name}`
    );
    return data;
  });
}

function Pokemon({ pokemon, setPokemon }) {
  const { isLoading, data } = usePokemon(pokemon);
  return (
    <div>
      <a href="#" onClick={() => setPokemon(pokemon.name)}>
        Back to the list
      </a>
      {isLoading ? (
        <p>loading...</p>
      ) : (
        <div>
          <h1>{pokemon}</h1>
          <img src={data.sprites.front_default} alt={pokemon} />
        </div>
      )}
    </div>
  );
}

function PokemonList({ setPokemon }) {
  const { isLoading, data } = usePokemonList();
  return (
    <div>
      {isLoading ? (
        <p>loading...</p>
      ) : (
        <ul>
          {data.map((pokemon) => (
            <li key={pokemon.name}>
              <a onClick={() => setPokemon(pokemon.name)} href="#">
                {pokemon.name}
              </a>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

1 Answers

The pokemon variable only holds a string value and is not an object with a name property on it. So in your Pokemon component when you pass pokemon.name in setPokemon function you are essentially passing an undefined value because the property name doesn't exist on the string.

And based on the conditional rendering you are doing in the App component since undefined is a falsy value, it renders PokemonList component instead of retaining the Pokemon component. To retain the Pokemon component, use setPokemon(pokemon) instead of setPokemon(pokemon.name).

function Pokemon({ pokemon, setPokemon }) {
  //pokemon variable is of string type.
  console.log(pokemon) //Prints the selected pokemon
  const { isLoading, data } = usePokemon(pokemon);
  return (
    <div>
      <a href="#" onClick={() => setPokemon(pokemon.name)}> {/* Passing pokemon.name is passing a property value that doesn't exist on the object*/}
        Back to the list
      </a>

To avoid going back to the list, set the pokemon to its actual name or a non-falsy value.

<a href="#" onClick={() => setPokemon(pokemon)}>
        Back to the list
</a>
Related