4

I was wondering if it were possible to call a child's function inside the parent?

For example, can I use useRef to create a reference to the child and then call the function like that? Or is there another way?

// Parent
const init = () => {
const childRef = useRef();
childRef.current.child();
}

// Child
const init = () => {
function child() {

}
}
Papi
  • 255
  • 1
  • 2
  • 13

5 Answers5

6

So you need to use useImperativeHandle hook and wrap the child in forwardRef Hoc. useImperativeHandle gives access to functions which are written inside it to the parent component.

  const Child = forwardRef((props,ref)=>{
     useImperativeHandle(ref, () => ({
        test: () => {
           //do something
        }
     }));
    });

in parent

const childRef= useRef();
<Child ref={childRef} />

Execute test function

childRef.current.test();
Sujit.Warrier
  • 2,815
  • 2
  • 28
  • 47
1

By using ref you can point it out to a function too,

parent component,

export default function App() {
  const childFnRef = useRef(null);
  const callChildFn = () => {
    if (childFnRef?.current) {
      childFnRef.current("valueOne", "valueTwo", "valueThree");
    }
  }
  return (
    <div>
      <h1>Parent component</h1>
      <ChildComponent ref={childFnRef} />
      <button onClick={callChildFn}>call child fn</button>
    </div>
  );
}

child component

//Ref forwarding is an opt-in feature that lets some components take a ref they receive,
//and pass it further down (in other words, “forward” it) to a child.
const ChildComponent = forwardRef((props, ref) => {
  const childFn = (paramOne, paramTwo, paramThree) => {
    console.log("calling child fn... params are: ", paramOne, paramTwo, paramThree);
  };

  ref.current = childFn;

  return (
    <h2>child component</h2>
  );
})

demo

Kalhan.Toress
  • 21,683
  • 8
  • 68
  • 92
  • Can I pass data down to the child too? I believe this works but for some reason `callChildFn(dataDown, wallArr, scene);` for example is not sending them down – Papi Oct 09 '20 at 04:39
  • @StasysMeclazcke updated, you have to pass the parameters from the parent as your comment, and the child function should accept the params, `const childFn = (paramOne, paramTwo, paramThree) => {....` – Kalhan.Toress Oct 09 '20 at 04:51
  • Can we have only an event handler bound to ref.current or multiple values can be added? – Rohitha Oct 09 '20 at 05:28
  • 1
    ` ref.current` should hold only one value, but you can be tricky to hold and object with functions – Kalhan.Toress Oct 09 '20 at 05:35
0

When you use useRef you must have current after function. Like this

const childRef = useRef();
childRef.current.child();

An example in document: https://reactjs.org/docs/hooks-reference.html#useref

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}
Anhdevit
  • 1,926
  • 2
  • 16
  • 29
  • Thank you but I am wondering if I can use a function from the child component. Not trying to return any html – Papi Oct 09 '20 at 04:15
0

Yes, but only if the child component is class component.

Because functional component does not have an instance.

Let's say your child component is a class-based then you just need to have a createRef() inside parent and then pass that to the child.

Then, you can collect that instance from .current property of the ref and then trigger it.

Example,

Parent Component's constructor

this.childRef = React.createRef();

Parent Component's render

 render() {
return <ChildComponent ref={this.childRef} />
}

Child Component

class ChildComponent extends React.Component {
    constructor(props) {
       super(props);
    }

    doSomeThing = () => {}

And then at any event handler, you can execute child function as this.childRef.current.doSomeThing();

Reference: https://reactjs.org/docs/refs-and-the-dom.html#accessing-refs

Kevin Moe Myint Myat
  • 1,916
  • 1
  • 10
  • 19
0

May be someone looking for functional component. Here is heck without forwardRef and imperative Handler.

In Parent create child Ref like this, const childRef = useRef()

In Child give ref passed from parent => ChildComponent ref={childRef} />

And finally in Parent use like this, childRef.current.goToIndex({index:1)}