I’m trying to create an pokedex app. In my app.js, I use an useEffect to make an API call then I use a child component to detail each card.
What I’m trying to do is when an user click on a card, app.js retrieve the selected pokemon’s data which later will be used to open Modal and show the selected pokemon’s infos.
On app.js, I create a props handleClickparent which is a function to console.log my data from PokemonCard compenent.
On app.js :
import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";
import React, { useState, useEffect } from "react";
import PokemonCard from "./component/PokemonCard";
function App() {
const [pokemonList, setPokemonList] = useState([]);
const [findPokemon, setFindPokemon] = useState("");
const [pokemonInfos, setPokemonInfos] = useState(null);
//Function for API Call
const searchPokemon = async () => {
const rawData = await fetch("https://pokeapi.co/api/v2/pokemon?limit=150");
const data1 = await rawData.json();
const data2 = await Promise.all(
data1.results.map((data) =>
fetch(`https://pokeapi.co/api/v2/pokemon/${data.name}`).then((data) =>
data.json()
)
)
);
setPokemonList(data2);
};
//Console.log data from PokemonCard component
const getData = (pokemon) => {
return console.log(pokemon);
};
//Initialize component
useEffect(() => {
searchPokemon();
}, []);
return (
<div>
<h5 className="title">Pokedex</h5>
<div className="SearchBar">
<input
className="Input"
type="search"
placeholder="...Search Pokemon"
onChange={(e) => setFindPokemon(e.target.value)}
value={findPokemon}
></input>
</div>
<PokemonCard
pokemonList={pokemonList}
searchValue={findPokemon}
handleClickParent={getData}
/>
</div>
);
}
export default App;
PokemonCard component
import React, { useEffect, useState } from "react";
import "../App.css";
function PokemonCard({ pokemonList, searchValue }, props) {
//using Hook to change the value when the user is hovering or selecting on a card
const [IsHovering, setIsHovering] = useState(-1);
const [selectIndex, setSelectIndex] = useState(-1);
//On click I send the select pokemon infos to the parent component
const handleClick = (pokemon) => {
console.log(pokemon);
props.handleClickParent(pokemon);
};
return (
<div className="RowCard">
{pokemonList
.filter((pokemon) => {
return pokemon.name.match(searchValue);
})
.map((pokemon, i) => {
return (
<div
key={i}
className={`Card ${IsHovering === i ? "HoveringCard" : ""}`}
onMouseEnter={() => setIsHovering(i)}
onMouseLeave={() => setIsHovering(-1)}
onClick={() => handleClick(pokemon)}
>
<p>{pokemon.name}</p>
<img
className="ImgPokemon"
src={`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/${pokemon.id}.png`}
></img>
</div>
);
})}
</div>
);
}
export default PokemonCard;
However an error is shown on my console :
PokemonCard.js:13 Uncaught TypeError: props.handleClickParent is not a function
at handleClick (PokemonCard.js:13:1)
at onClick (PokemonCard.js:29:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
at invokeGuardedCallback (react-dom.development.js:4277:1)
at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:4291:1)
at executeDispatch (react-dom.development.js:9041:1)
at processDispatchQueueItemsInOrder (react-dom.development.js:9073:1)
at processDispatchQueue (react-dom.development.js:9086:1)
at dispatchEventsForPlugins (react-dom.development.js:9097:1)
h
If anyone sees what’s wrong with my code, I would be more than happy if you would share your idea.
Thanks in advance
2
Answers
You are destructuring
pokemonList
andsearchValue
, but adding aprops
as a second parameter of your component. Either destructure yourhandleClickParent
or only use props andprops.pokemonList
(or other props) to acces your props. There is usually no second parameter in a function component, unless you are using something likeforwardRef
which will add the ref as second argument.function PokemonCard({ pokemonList, searchValue, handleCickParent }) {...}
or
function PokemonCard(props) {...}
The issue seems to be with the way you are passing the handleClickParent function to the PokemonCard component. In the App.js file, you are passing the function as a prop named handleClickParent, but in the PokemonCard.js file, you are trying to access it as props.handleClickParent.
you should replace this line:
with this:
using the "rest" operator (…props) will collect any additional props passed to the component and store them in an object called props, which can be used within the component body as needed.
or you can remove the props argument from the PokemonCard function definition, and simply use handleClickParent directly: