I currently have a function that I want to pass to the a child that is two levels deep. My function is :
const addToTrip= (isChecked, coordinates, title, yelpID)=>{
console.log("added to trip ")
if(isChecked){
setWaypoints((waypoints)=>[...waypoints, {name:title, yelp_id:yelpID, coordinates:coordinates}])
} else if(!isChecked){
const newWaypoints = waypoints.filter((waypoint)=>waypoint.yelp_id !== yelpID)
setWaypoints(newWaypoints)
}
}
My function is used in my Businesses
component and it is rendered under certain conditions
{hikes.length>0 && (
<Businesses
hikes = {hikes}
addToTrip = {addToTrip}
/>
)}
When I initially run my app and hikes
is empty, I thought my function isnt supposed to be invoked until I call it, but it is being called because my waypoints
state gets set twice and my console.log("added to trip ")
triggers twice as well.
I tried to go about it with changing my render logic of Businesses
to
{hikes.length>0 && (
<Businesses
hikes = {hikes}
// addToTrip = {addToTrip}
addToTrip = {()=>addToTrip}
/>
)}
With the above code, I dont actually get my console log statements and my waypoints
state remain untouched. Now the issue with this is I cant seem to use this function in my child component properly like I was able to in my first approach. I know that I am calling the addToTrip
function successfully as my console.log will print as expected, but it's not detecting my input parameters any more.
Here is my first child component:
export const Businesses = (props)=>{
const {hikes, addToTrip} = props
return(<>
<div className="businessesColumn">
{hikes.map(hike=>(
<BusinessCard ...
/>
)}
Here is my second child component:
export const BusinessCard = (props)=>{
const {img, title, location, description, star, reviewCount, addToTrip, coordinates, yelpID} = props;
const [isChecked, setIsChecked] = useState(false);
useEffect(()=>{
console.log(isChecked)
addToTrip(isChecked, coordinates, title, yelpID)
},[isChecked])
const handleOnChange = ()=>{
setIsChecked(!isChecked);
}
return (...)
Q1: How come my function is called even when I am not calling it when I am passing it as addToTrip = {addToTrip}
? I know react creates the function on every render, unless I usecallback, but is it suppose to "call" it?
Q2: How am I able to pass parameters from child component if I were to pass function as props with addToTrip = {()=>addToTrip}
Q3: Does React create a new addToTrip
object for each component it is passed to? Ive noticed that my addToTrip
gets called for each component that requires it but doesnt even call it
I greatly appreciate any help.
CodePudding user response:
I can tell in this case that it may not be extremely relevant. But, if you have a huge state tree logic where you would need the same state being passed down from a grandfather component (parent of a parent) to a grandchild (child of a child), then React has a context that helps React JS Context Docs.
For Q1, I believe addToTrip is accurate since you are passing down the function reference (as opposed to passing down something like addToTrip()).
CodePudding user response:
Q1: How come my function is called even when I am not calling it when I am passing it as addToTrip = {addToTrip}? I know react creates the function on every render, unless I usecallback, but is it suppose to "call" it?
It actually does not trigger your function but passes down to child components only. In this context, you don't need to call useCallback
, because your function is never modified.
Q2: How am I able to pass parameters from child component if I were to pass function as props with addToTrip = {()=>addToTrip}
addToTrip = {()=>addToTrip}
is not a proper way to call your function. It should be
addToTrip = {()=>addToTrip()}
(it will create a new function every time the component gets re-rendered). In this case, you can calluseCalback
to memoize your functionaddToTrip = {addToTrip}
(it won't create a new function but re-use the current function)
Q3: Does React create a new addToTrip object for each component it is passed to? Ive noticed that my addToTrip gets called for each component that requires it but doesnt even call it
The problem is from useEffect
. When your component get rendered, useEffect
will be triggered initially, and addToTrip(isChecked, coordinates, title, yelpID)
will get called. For the fix, you should move addToTrip
to handleOnChange
which is only triggered when you tick on checkboxes
const handleOnChange = ()=>{
setIsChecked(!isChecked);
addToTrip(!isChecked, coordinates, title, yelpID);
}