10

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:

enter image description here

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. enter image description here

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.

2
  • The solution you linked to is the correct solution for forwarding a ref to a child component and imperatively invoking a function. What isn't working for you in this implementation? Can you update your question to include what you tried and what the issue/error is? Commented Aug 3, 2021 at 20:00
  • Sure! I added how I used forwardRef following that solution link and the warning it gave me. Commented Aug 3, 2021 at 20:20

3 Answers 3

22

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}/>
  );
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! this solution worked. I was using useImperativeHandle incorrectly.
10 upvotes!!!!!
12

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} />;
  </>

}

1 Comment

Everyone seems to upvote this solution but no one came to say thank you because it kinda dirty in comparison of the accepted answer (i guess), but thank you i think it's a pretty useful solution in my case.
1

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 />)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.