Reputation: 137
I have some action buttons in parent components. On click of one of such buttons, I would like to trigger a function in the child component. Currently, I am trying to implement it using useRef hook. But the solution seems tedious and also gives me warning:
My current code looks like:
import React, {useContext, useEffect, useState, useRef} from 'react';
const ParentComponent = ({...props})=> {
const myRef = useRef();
const onClickFunction = () => {
if(myRef.current) {
myRef.current.childFunction();
}
}
return (
<ChildComponent ref = {myRef}/>
);
}
Child component
const ChildComponent = (({}, ref,{ actionButtons, ...props}) => {
const [childDataApi, setChildDataApi] = useState(null);
const childFunction = () => {
//update childDataApi and pass it to parent
console.log("inside refreshEntireGrid");
}
});
Firstly, is there a better solution then trying to trigger childFunction from parent ? For this I am following this solution:
Can't access child function from parent function with React Hooks
I tried adding forward ref but that threw error as well.
I also found out that lifting the state up could be another solution as well. But I am not able to understand how to apply that solution in my case. Can someone please help me with this.
Upvotes: 10
Views: 25651
Reputation: 365
One way to call a child component's function from its parent is with the useRef hook
const Parent = () => {
const childFunc = React.useRef(null)
return (
<>
<Child childFunc={childFunc} />
<button onClick={() => childFunc.current()}>Click me</button>
</>
)
}
const Child = ({ childFunc }) => {
React.useEffect(() => {
childFunc.current = alertUser
}, [childFunc.current])
function alertUser() {
alert('You clicked!')
}
return null
}
render(<Parent />)
Upvotes: 0
Reputation: 203542
The warning says you were using forwardRef
so with your snippet const ChildComponent = (({}, ref, { actionButtons, ...props }) => { .... }
I'll assume this is a typo in your question and you were actually doing const ChildComponent = React.forwardRef(({}, ref,{ actionButtons, ...props }) => { .... })
.
The issue here, and the warning message points this out, is that you are passing a third argument to forwardRef
when it only consumes two. It seems you destructure nothing from the first props
argument. From what I can tell you should replace the first argument with the third where it looks like you are doing some props destructuring.
const ChildComponent = React.forwardRef(({ actionButtons, ...props }, ref) => { .... }
From here you should implement the useImperativeHandle
hook to expose out the function from the child.
const ChildComponent = React.forwardRef(({ actionButtons, ...props }, ref) => {
const [childDataApi, setChildDataApi] = useState(null);
const childFunction = () => {
// update childDataApi and pass it to parent
console.log("inside refreshEntireGrid");
}
useImperativeHandle(ref, () => ({
childFunction
}));
...
return ( ... );
});
In the parent component:
const ParentComponent = (props) => {
const myRef = useRef();
const onClickFunction = () => {
myRef.current?.childFunction();
}
return (
<ChildComponent ref={myRef}/>
);
}
Upvotes: 22
Reputation: 13641
Something else you can try is to pass a prop to the child to indicate that the button has been clicked and use useEffect
in the child component to do something when that value changes.
const Child = props => {
useEffect(() => TriggeredFunc(), [props.buttonClicked]);
const TriggeredFunc = () => {
...
}
return '...';
}
const Parent = () => {
const [buttonClicked, setButtonClicked] = useState(0);
const onClick = e => {
setButtonClicked(buttonClicked++);
}
return <>
<button onClick={onClick}>My Button</button>
<Child buttonClicked={buttonClicked} />;
</>
}
Upvotes: 10