915

I have two components:

  1. Parent component
  2. Child component

I was trying to call Child's method from Parent, I tried this way but couldn't get a result:

class Parent extends Component {
  render() {
    return (
      <Child>
        <button onClick={Child.getAlert()}>Click</button>
      </Child>
      );
    }
  }

class Child extends Component {
  getAlert() {
    alert('clicked');
  }
 
  render() {
    return (
      <h1 ref="hello">Hello</h1>
    );
  }
}

Is there a way to call Child's method from Parent?

Note: Child and Parent components are in two different files.

xcopy
  • 2,248
  • 18
  • 24
N8FURY
  • 9,490
  • 3
  • 14
  • 14
  • You can make Inheritance Inversion (look it up here: https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e). That way you have access to instance of the component that you would be wrapping (thus you'll be able to access it's functions) – szpada87 Aug 15 '18 at 06:46

23 Answers23

1331

First off, let me express that this is generally not the way to go about things in React land. Usually what you want to do is pass down functionality to children in props, and pass up notifications from children in events (or better yet: dispatch).

But if you must expose an imperative method on a child component, you can use refs. Remember this is an escape hatch and usually indicates a better design is available.

Previously, refs were only supported for Class-based components. With the advent of React Hooks, that's no longer the case

Modern React with Hooks (v16.8+)

const { forwardRef, useRef, useImperativeHandle } = React;

// We need to wrap component in `forwardRef` in order to gain
// access to the ref object that is assigned using the `ref` prop.
// This ref is passed as the second parameter to the function component.
const Child = forwardRef((props, ref) => {

  // The component instance will be extended
  // with whatever you return from the callback passed
  // as the second argument
  useImperativeHandle(ref, () => ({

    getAlert() {
      alert("getAlert from Child");
    }

  }));

  return <h1>Hi</h1>;
});

const Parent = () => {
  // In order to gain access to the child component instance,
  // you need to assign it to a `ref`, so we call `useRef()` to get one
  const childRef = useRef();

  return (
    <div>
      <Child ref={childRef} />
      <button onClick={() => childRef.current.getAlert()}>Click</button>
    </div>
  );
};

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>

<div id="root"></div>

Documentation for useImperativeHandle() is here:

useImperativeHandle customizes the instance value that is exposed to parent components when using ref.

Legacy API using Class Components (>= react@16.4)

const { Component } = React;

class Parent extends Component {
  constructor(props) {
    super(props);
    this.child = React.createRef();
  }

  onClick = () => {
    this.child.current.getAlert();
  };

  render() {
    return (
      <div>
        <Child ref={this.child} />
        <button onClick={this.onClick}>Click</button>
      </div>
    );
  }
}

class Child extends Component {
  getAlert() {
    alert('getAlert from Child');
  }

  render() {
    return <h1>Hello</h1>;
  }
}

ReactDOM.render(<Parent />, document.getElementById('root'));
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>

Callback Ref API

Callback-style refs are another approach to achieving this, although not quite as common in modern React:

const { Component } = React;
const { render } = ReactDOM;

class Parent extends Component {
  render() {
    return (
      <div>
        <Child ref={instance => { this.child = instance; }} />
        <button onClick={() => { this.child.getAlert(); }}>Click</button>
      </div>
    );
  }
}

class Child extends Component {
  getAlert() {
    alert('clicked');
  }

  render() {
    return (
      <h1>Hello</h1>
    );
  }
}


render(
  <Parent />,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="app"></div>
rossipedia
  • 56,800
  • 10
  • 90
  • 93
  • 31
    I tired, but end up with this error "_this2.refs.child.getAlert is not a function" – N8FURY Jun 21 '16 at 17:58
  • and I need to mention that, these components are in two separate files and I am importing the child to the parent – N8FURY Jun 21 '16 at 18:09
  • In that case, I'd suggest editing your question to reflect that they are in two different files, and posting the exact code that is causing problems. – rossipedia Jun 21 '16 at 18:24
  • This doesn't work when we use `react-redux` while using `mapStateToProps` and `mapDispatchToProps` while exporting the class. – psr Dec 25 '16 at 15:22
  • 26
    That's because `connect` returns a higher order component that wraps your original instance. You'll need to call `getWrappedInstance()` on the connected component first to get your original component. Then you can call instance methods on that. – rossipedia Dec 25 '16 at 19:07
  • 22
    This is not really a good pattern. Not to mention string refs are frowned upon. It's better to pass props into the child component and then have a button click in the parent change the parent's state, and pass a state item into the child which will trigger the child's `componentWillReceiveProps`, and use that as a trigger. – ffxsam Mar 30 '17 at 16:41
  • 12
    No, it's not _usually_ the best pattern, it's more of an escape hatch when you need it, and should be used only in emergencies. Also, this answer was written when string refs were still around, and you're right that they're not the "correct" way of doing things these days. – rossipedia Mar 30 '17 at 17:58
  • @ffxsam there are some cases you can't really do what's best, which you mentioned. – technophyle Aug 02 '17 at 21:21
  • 1
    Question about this, when referencing a child components methods in `componentDidMount()` is it bad practice to access one which modifies that child components state? – James Ives Sep 04 '17 at 00:14
  • 6
    for those getting `_this2.clickChild is not a function` this was the correct application of a ref : https://github.com/kriasoft/react-starter-kit/issues/909#issuecomment-252969542 – tatsu Sep 06 '17 at 09:36
  • @JamesIves sorry for the late response, but as long as that child method is calling `setState` to alter its own state, then no, there shouldn't be a problem with it. – rossipedia Nov 12 '17 at 22:28
  • 104
    If best practice is to create a maze of logic to do something as simple as calling a child component's method - then I disagree with best practice. – aaaaaa Dec 03 '18 at 17:47
  • 5
    This was much easier with classes then with the new hooks function components. I can't believe there is not an easier way than the hooks example above using the "forwardRef". What a mess it makes! – Lambert Mar 06 '19 at 21:57
  • 3
    @rossipedia you say _"Usually what you want to do is pass down functionality to children in props, and pass up notifications from children in events."_ could you please provide a link to React documentation for this part? I didn't find the part of notification from children in events. Thank you very much! – Tenaciousd93 Apr 26 '19 at 06:19
  • @ffxsam React has changed a lot over the years, is your explanation still the "correct" way of accessing a child component's method? I would love to see your comment made into an answer. It does however seem convoluted, and as another commenter noted if that's best practice for seemingly simple logic the I disagree with best practice. What I haven't heard anyone say yet is **why** this is a bad pattern or bad practice. – Matt K Jun 10 '19 at 14:21
  • 1
    @MattK his comment was over two years ago, my last edit to this answer was a month ago. I try to keep the answer as up to date as I can – rossipedia Jun 10 '19 at 15:38
  • @rossipedia Fair enough but can you update your answer to explain why accessing a child component's method is "not the way to go about things" and "is an escape hatch" as you have stated. The logic seems simple enough and it works. What makes other design patterns "better" than using hooks or class components? – Matt K Jun 11 '19 at 18:52
  • 1
    That's a much larger and broader topic than the original question, and not one well suited for Stack Overflow. – rossipedia Jun 11 '19 at 22:07
  • 4
    @rossipedia That's not the case at all. In fact, code only answers are discouraged on SO. A short explanation of "why" is always encouraged and goes a long way to helping someone become a better programmer and not just a copy-paste ninja. – Matt K Jul 02 '19 at 15:46
  • How does this work if the parent is a legacy class component and the child is a function component using forwardRef.? Setting ref in the parent is throwing a warning - "Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?". – iPhoney Aug 21 '19 at 08:47
  • When I do `Using Class Components` with my 16.8 , I have form questions in tabs that no longer let me check/click/select the radio buttons and checkboxes - a bit strange. ( for me its parent page has Tabs with each tab child a js file ) –  Oct 29 '19 at 19:44
  • 1
    i tried the functional component solution and i got this error : Function components cannot have refs. Did you mean to use React.forwardRef()? Have anyone an idea about this ? – VenomBerry Jan 24 '20 at 17:06
  • The very first line of the Function Component example shows the usage of `forwardRef`. – rossipedia Jan 24 '20 at 22:32
  • @rossipedia, i used forwardRef but still have the same error. – VenomBerry Jan 27 '20 at 09:20
  • 2
    Why is it bad practice? Lets say you have a tree view control. Each node is a sub component. But you want to be able to collapse all nodes from the parent. Super normal business scenario. How would you implement this without sending something to the children? – Thomas Segato Feb 01 '20 at 18:44
  • How would you do it with passing parameters as you describe as best practices? Can you somehow pass a toggle variable that somehows triggers the function in the child? – Thomas Segato Feb 01 '20 at 18:48
  • 3
    @ThomasSegato you can write the toggle function in parent component that set a toggle variable and send that variable as a props to each child component. Bad practice is to write that toggle function in child component and try to trigger it from parent. This method is for certain cases only where you absolutely need to trigger child function from parent component. I myself just ran into one and this method helped me. – dup.titung Apr 24 '20 at 07:39
  • Cannot add property current, object is not extensible => in hooks – Vikas chhabra May 03 '20 at 01:16
  • 2
    Just to inform, according to React team => imperative code using refs should be avoided in most cases. – Hasan Sefa Ozalp May 06 '20 at 11:19
  • why we need use `useImperativeHandle`?. What's the problem if I use `ref.current = { getAlert() { alert("getAlert from Child"); }}` – nuclear Oct 25 '20 at 13:16
  • 3
    Aaaand this is why I won't use React. You try it for 5 minutes and immediately run into this issue every time. I don't know why they can't just admit it's a bad design pattern. If you can't call methods on child objects then what is the point of embracing OO concepts in the first place? They always imply there's a "react way" to do it, but in my experiences, more often than not there just isn't. – JeneralJames Nov 22 '20 at 22:21
  • 1
    @dup.titung the problem with that "control the child with props" philosophy is that you can't execute logic in response to it without jumping through hoops. You have to rather un-elegantly listen to changes to props, comparing the previous to the current and determining if you need to do something. All this just to replicate the behaviour of a simple function call. – JeneralJames Nov 22 '20 at 22:24
  • 6
    This is a good answer, and works fine for me. However, the thread is missing a solid explanation as to why this 'bad practice'. I get it, 'react team said so' and 'use redux' 'use events'... sounds complicated. having a ref to a child function makes a lot of sense to me. I have a dynamically generated form inside of a generic modal wrapper, then I want the parent modal submit to go from disabled to enabled once the child form validates itself. It just needs to be some kind of a 2-way street, I'm not hearing great reasons why this would be a bad way to accomplish that. – Brooks DuBois Mar 11 '21 at 23:08
  • I followed the same but in my parent component childRef.current is undefined. Unable to find out the solution. Any help please ? – Amir May 25 '21 at 12:33
  • How do you handle these two scenarios: `1. Parent class component with child Hook` and `2. Parent Hook with child class component` ? – Kasra Oct 06 '21 at 09:55
  • @Kasra please see [here](https://codesandbox.io/s/musing-dhawan-22qgd?file=/src/App.js) – rossipedia Dec 27 '21 at 19:09
  • I think the "modern react with hooks" example above should read: `getAlert: () => { ... }`. See [doc](https://reactjs.org/docs/hooks-reference.html#useimperativehandle). – Luis Cantero Jan 20 '22 at 09:07
  • I had same problem, you are right, this isn't react way, I ended up using Subscription (Similar to SignalR) to solve my problem. – Milad Jun 08 '22 at 19:12
  • Great answer. The forwardRef, useRef trick saved me Was using react-table and needed to pass setGlobalFilter out to some parent so they could filter the table when an input changes. – Yaron Levi Jun 14 '22 at 19:08
212

You can use another pattern here:

class Parent extends Component {
 render() {
  return (
    <div>
      <Child setClick={click => this.clickChild = click}/>
      <button onClick={() => this.clickChild()}>Click</button>
    </div>
  );
 }
}

class Child extends Component {
 constructor(props) {
    super(props);
    this.getAlert = this.getAlert.bind(this);
 }
 componentDidMount() {
    this.props.setClick(this.getAlert);
 }
 getAlert() {
    alert('clicked');
 }
 render() {
  return (
    <h1 ref="hello">Hello</h1>
  );
 }
}

What it does is to set the parent's clickChild method when child is mounted. In this way when you click the button in parent it will call clickChild which calls child's getAlert.

This also works if your child is wrapped with connect() so you don't need the getWrappedInstance() hack.

Note you can't use onClick={this.clickChild} in parent because when parent is rendered child is not mounted so this.clickChild is not assigned yet. Using onClick={() => this.clickChild()} is fine because when you click the button this.clickChild should already be assigned.

daaawx
  • 3,273
  • 2
  • 17
  • 16
brickingup
  • 2,733
  • 1
  • 14
  • 10
136

Alternative method with useEffect:

Parent:

const [refresh, doRefresh] = useState(0);
<Button onClick={() => doRefresh(prev => prev + 1)} />
<Children refresh={refresh} />

Children:

useEffect(() => {
    performRefresh(); //children function of interest
  }, [props.refresh]);
Freewalker
  • 6,329
  • 4
  • 51
  • 70
tonymayoral
  • 4,797
  • 2
  • 26
  • 27
  • 6
    Ps. If your desire is just to re-render the form (for example, to reset the input fields) then you don't even need to include the useEffect, you can just make the prop being sent into the component change – Matt Fletcher Jun 08 '20 at 11:07
  • @tonymayoral Is there a way we can have useState inside Child component and use doRefresh from Parent. In my case i do not want my Parent to re-render. – Neel Dsouza Oct 26 '20 at 07:09
  • 2
    This solution works great for refreshing or calling a function on several children at once! – Blake Allen Apr 08 '21 at 03:04
  • @MattFletcher without `useEffect`, you might receive infinite loops – hik hyper Apr 23 '21 at 02:39
  • 4
    This works great. Note you can also check `(props.refresh !== 0)` to avoid running the function on the initial loop. – David Figatner Oct 24 '21 at 13:28
  • this works. But don't let the numbers on doRefresh keep increasing. I usually use boolean negation. `const [refresh, doRefresh] = useState(false);` and when changing state I just reverse the state like `doRefresh(!refresh)`. – Yanwar Sky Oct 10 '22 at 18:01
  • It is refreshing parent component! We want only to call performRefresh() in the child component, but in this case whole child component is recreated... – Szynkie Aug 28 '23 at 15:48
89

Here I will give you the four possible combinations that can happen:

  1. Class Parent | Hook Child
  2. Hook Parent | Class Child
  3. Hook Parent | Hook Child
  4. Class Parent | Class Child

1. Class Parent | Hook Child

class Parent extends React.Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
  }

  render() {
    return (<View>
      <Child ref={this.myRef}/>
      <Button title={'call me'}
              onPress={() => this.myRef.current.childMethod()}/>
    </View>)
  }
}

const Child = React.forwardRef((props, ref) => {

  useImperativeHandle(ref, () => ({
    childMethod() {
      childMethod()
    }
  }))

  function childMethod() {
    console.log('call me')
  }

  return (<View><Text> I am a child</Text></View>)
})

2. Hook Parent | Class Child

function Parent(props) {

  const myRef = useRef()

  return (<View>
    <Child ref={myRef}/>
    <Button title={'call me'}
            onPress={() => myRef.current.childMethod()}/>
  </View>)
}

class Child extends React.Component {

  childMethod() {
    console.log('call me')
  }

  render() {
    return (<View><Text> I am a child</Text></View>)
  }
}

3. Hook Parent | Hook Child

function Parent(props) {

  const myRef = useRef()

  return (<View>
    <Child ref={myRef}/>
    <Button title={'call me'}
            onPress={() => myRef.current.childMethod()}/>
  </View>)
}

const Child = React.forwardRef((props, ref) => {

  useImperativeHandle(ref, () => ({
    childMethod() {
      childMethod()
    }
  }))

  function childMethod() {
    console.log('call me')
  }

  return (<View><Text> I am a child</Text></View>)
})

4. Class Parent | Class Child

class Parent extends React.Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
  }

  render() {
    return (<View>
      <Child ref={this.myRef}/>
      <Button title={'call me'}
              onPress={() => this.myRef.current.childMethod()}/>
    </View>)
  }
}

class Child extends React.Component {

  childMethod() {
    console.log('call me')
  }

  render() {
    return (<View><Text> I am a child</Text></View>)
  }
}
Shamseer Ahammed
  • 1,787
  • 2
  • 20
  • 25
Kasra
  • 1,959
  • 1
  • 19
  • 29
  • For **Hook Parent | Hook Child** why do you have to use `forwardRef`? Why can't you just access the `ref` inside Child via `props.ref` and then assign with `props.ref.childMethod=childMethod`? – Kernel James Mar 08 '22 at 03:40
  • 1
    The second ref argument only exists when you define a component with React.forwardRef call. Regular function or class components don’t receive the ref argument, and ref is not available in props either. – Kasra Mar 21 '22 at 12:21
  • 2
    This is awesomeness.neat clean answr. I used the class | class and works smoothly. rest of 3 types are also useful. – CrackerKSR Aug 14 '22 at 07:55
34

https://facebook.github.io/react/tips/expose-component-functions.html for more answers ref here Call methods on React children components

By looking into the refs of the "reason" component, you're breaking encapsulation and making it impossible to refactor that component without carefully examining all the places it's used. Because of this, we strongly recommend treating refs as private to a component, much like state.

In general, data should be passed down the tree via props. There are a few exceptions to this (such as calling .focus() or triggering a one-time animation that doesn't really "change" the state) but any time you're exposing a method called "set", props are usually a better choice. Try to make it so that the inner input component worries about its size and appearance so that none of its ancestors do.

Community
  • 1
  • 1
Mike Tronic
  • 540
  • 3
  • 5
  • 8
    Here is the source of this answer: https://discuss.reactjs.org/t/is-it-bad-practice-to-call-child-component-methods-from-parent/1821/2. No problems with citing others, but at least put in some reference. – Jodo Oct 11 '17 at 07:46
  • 7
    How exactly does this break encapsulation any more than props? – Timmmm Jan 31 '20 at 16:47
  • my child component is currently managing a large amount of data, and it doesn't make sense to me to bring all that data up into the parent, given that the child is used in many places/pages, and this would require changing a lot of parents just to wire the child the needed data. In this one page, the parent needs access to a derivative of the data, and is therefore calling the child's method. What is the "correct" way to do this that wouldn't require large amounts of boilerplate across the site? – fileyfood500 Aug 09 '23 at 21:18
29

I wasn't satisfied with any of the solutions presented here. There is actually a very simple solution that can be done using pure Javascript without relying upon some React functionality other than the basic props object - and it gives you the benefit of communicating in either direction (parent -> child, child -> parent). You need to pass an object from the parent component to the child component. This object is what I refer to as a "bi-directional reference" or biRef for short. Basically, the object contains a reference to methods in the parent that the parent wants to expose. And the child component attaches methods to the object that the parent can call. Something like this:

// Parent component.
function MyParentComponent(props) {

   function someParentFunction() {
      // The child component can call this function.
   }

   function onButtonClick() {
       // Call the function inside the child component.
       biRef.someChildFunction();
   }

   // Add all the functions here that the child can call.
   var biRef = {
      someParentFunction: someParentFunction
   }

   return <div>
       <MyChildComponent biRef={biRef} />
       <Button onClick={onButtonClick} />
   </div>;
}


// Child component
function MyChildComponent(props) {

   function someChildFunction() {
      // The parent component can call this function.
   }


   function onButtonClick() {
      // Call the parent function.
      props.biRef.someParentFunction();
   }

   // Add all the child functions to props.biRef that you want the parent
   // to be able to call.
   props.biRef.someChildFunction = someChildFunction;

   return <div>
       <Button onClick={onButtonClick} />
   </div>;
}

The other advantage to this solution is that you can add a lot more functions in the parent and child while passing them from the parent to the child using only a single property.

An improvement over the code above is to not add the parent and child functions directly to the biRef object but rather to sub members. Parent functions should be added to a member called "parent" while the child functions should be added to a member called "child".

// Parent component.
function MyParentComponent(props) {

   function someParentFunction() {
      // The child component can call this function.
   }

   function onButtonClick() {
       // Call the function inside the child component.
       biRef.child.someChildFunction();
   }

   // Add all the functions here that the child can call.
   var biRef = {
      parent: {
          someParentFunction: someParentFunction
      }
   }

   return <div>
       <MyChildComponent biRef={biRef} />
       <Button onClick={onButtonClick} />
   </div>;
}


// Child component
function MyChildComponent(props) {

   function someChildFunction() {
      // The parent component can call this function.
   }


   function onButtonClick() {
      // Call the parent function.
      props.biRef.parent.someParentFunction();
   }

   // Add all the child functions to props.biRef that you want the parent
   // to be able to call.
   props.biRef {
       child: {
            someChildFunction: someChildFunction
       }
   }

   return <div>
       <Button onClick={onButtonClick} />
   </div>;
}

By placing parent and child functions into separate members of the biRef object, you 'll have a clean separation between the two and easily see which ones belong to parent or child. It also helps to prevent a child component from accidentally overwriting a parent function if the same function appears in both.

One last thing is that if you note, the parent component creates the biRef object with var whereas the child component accesses it through the props object. It might be tempting to not define the biRef object in the parent and access it from its parent through its own props parameter (which might be the case in a hierarchy of UI elements). This is risky because the child may think a function it is calling on the parent belongs to the parent when it might actually belong to a grandparent. There's nothing wrong with this as long as you are aware of it. Unless you have a reason for supporting some hierarchy beyond a parent/child relationship, it's best to create the biRef in your parent component.

Johann
  • 27,536
  • 39
  • 165
  • 279
19

I hope I'm not repeating anything from above but what about passing a callback prop that sets the function in the parent? This works and is pretty easy. (Added code is between the ////'s)

class Parent extends Component {
  ///// 
  getAlert = () => {} // initial value for getAlert

  setGetAlertMethod = (newMethod) => {
    this.getAlert = newMethod;
  }
  /////

  render() {
    return (
      <Child setGetAlertMethod={this.setGetAlertMethod}>
        <button onClick={this.getAlert}>Click</button>
      </Child>
      );
    }
  }



class Child extends Component {
  /////
  componentDidMount() {
    this.props.setGetAlertMethod(this.getAlert);
  }
  /////

  getAlert() => {
    alert('clicked');
  }

  render() {
    return (
      <h1 ref="hello">Hello</h1>
    );
  }
}
Peter Hollingsworth
  • 1,870
  • 1
  • 18
  • 18
  • You `getAlert` definition inside the `Child` has typo. It should be ` getAlert = () => { alert('clicked'); } ` Secondly, why `` is inside the ``? The whole point is calling child method FROM PARENT. – canbax Jan 07 '22 at 06:44
  • if you now call `getAlert()` from the parent, it will run the getAlert defined in the child (e.g. it will `alert('clicked')`). You're passing the child a function that the child can use to assign a function _in the parent_. – Peter Hollingsworth Aug 01 '22 at 16:25
17

I'm using useEffect hook to overcome the headache of doing all this so now I pass a variable down to child like this:

import { useEffect, useState } from "react";

export const ParentComponent = () => {
  const [trigger, setTrigger] = useState(false);

  return (
    <div onClick={() => { setTrigger(trigger => !trigger); }}>
      <ChildComponent trigger={trigger}></ChildComponent>
    </div>
  );
};

export const ChildComponent = (props) => {
  const triggerInvokedFromParent = () => {
    console.log('TriggerInvokedFromParent');
  };

  useEffect(() => {
    triggerInvokedFromParent();
  }, [props.trigger]);

  return <span>ChildComponent</span>;
};
Black Mamba
  • 13,632
  • 6
  • 82
  • 105
17

you can use ref to call the function of the child component from the parent

Functional Component Solution

in functional component, you have to use useImperativeHandle for getting ref into a child like below

import React, { forwardRef, useRef, useImperativeHandle } from 'react';
export default function ParentFunction() {
    const childRef = useRef();
    return (
        <div className="container">
            <div>
                Parent Component
            </div>
            <button
                onClick={() => { childRef.current.showAlert() }}
            >
            Call Function
            </button>
            <Child ref={childRef}/>
        </div>
    )
}
const Child = forwardRef((props, ref) => {
    useImperativeHandle(
        ref,
        () => ({
            showAlert() {
                alert("Child Function Called")
            }
        }),
    )
    return (
       <div>Child Component</div>
    )
})

Class Component Solution

Child.js

import s from './Child.css';

class Child extends Component {
 getAlert() {
    alert('clicked');
 }
 render() {
  return (
    <h1>Hello</h1>
  );
 }
}

export default Child;

Parent.js

class Parent extends Component {
 render() {
  onClick() {
    this.refs.child.getAlert();
  }
  return (
    <div>
      <Child ref="child" />
      <button onClick={this.onClick}>Click</button>
    </div>
  );
 }
}
Muhammad Numan
  • 23,222
  • 6
  • 63
  • 80
  • This is the reson why I like the child component to be class not functional component. Way easier to handle with refs. – Jeroi Jan 07 '23 at 01:45
11

We can use refs in another way as-

We are going to create a Parent element, it will render a <Child/> component. As you can see, the component that will be rendered, you need to add the ref attribute and provide a name for it.
Then, the triggerChildAlert function, located in the parent class will access the refs property of the this context (when the triggerChildAlert function is triggered will access the child reference and it will has all the functions of the child element).

class Parent extends React.Component {
    triggerChildAlert(){
        this.refs.child.callChildMethod();
        // to get child parent returned  value-
        // this.value = this.refs.child.callChildMethod();
        // alert('Returned value- '+this.value);
    }

    render() {
        return (
            <div>
                {/* Note that you need to give a value to the ref parameter, in this case child*/}
                <Child ref="child" />
                <button onClick={this.triggerChildAlert}>Click</button>
            </div>
        );
    }
}  

Now, the child component, as theoretically designed previously, will look like:

class Child extends React.Component {
    callChildMethod() {
        alert('Hello World');
        // to return some value
        // return this.state.someValue;
    }

    render() {
        return (
            <h1>Hello</h1>
        );
    }
}

Here is the source code-
Hope will help you !

S.Yadav
  • 4,273
  • 3
  • 37
  • 44
11

For functional components easiest way is

Parent Component

parent.tsx

import React, { useEffect, useState, useRef } from "react";
import child from "../../child"

const parent: React.FunctionComponent = () => {
  const childRef: any = useRef();
    
const onDropDownChange: any = (event): void => {
    const target = event.target;
    childRef.current.onFilterChange(target.value);
};

return <child ref={childRef} />
}
export default parent;

Child Component

child.tsx

import React, {   useState,   useEffect,   forwardRef,   useRef,   useImperativeHandle, } from "react";

const Child = forwardRef((props, ref) => {
 useImperativeHandle(ref, () => ({
    onFilterChange(id) {
      console.log("Value from parent", id)
    },
  }));
})

Child.displayName = "Child";

export default Child;
Rohit Parte
  • 3,365
  • 26
  • 26
  • 1
    closing curly brace in parent isnt correct, please fix – abitcode Sep 10 '21 at 05:50
  • This answer is not adding any more information than what was already stated (and better) in the answer from @rossipedia. And the code is mangled. – Martin Mar 18 '23 at 08:28
9

If you are doing this simply because you want the Child to provide a re-usable trait to its parents, then you might consider doing that using render-props instead.

That technique actually turns the structure upside down. The Child now wraps the parent, so I have renamed it to AlertTrait below. I kept the name Parent for continuity, although it is not really a parent now.

// Use it like this:

  <AlertTrait renderComponent={Parent}/>


class AlertTrait extends Component {
  // You will need to bind this function, if it uses 'this'
  doAlert() {
    alert('clicked');
  }
  render() {
    return this.props.renderComponent({ doAlert: this.doAlert });
  }
}

class Parent extends Component {
  render() {
    return (
      <button onClick={this.props.doAlert}>Click</button>
    );
  }
}

In this case, the AlertTrait provides one or more traits which it passes down as props to whatever component it was given in its renderComponent prop.

The Parent receives doAlert as a prop, and can call it when needed.

(For clarity, I called the prop renderComponent in the above example. But in the React docs linked above, they just call it render.)

The Trait component can render stuff surrounding the Parent, in its render function, but it does not render anything inside the parent. Actually it could render things inside the Parent, if it passed another prop (e.g. renderChild) to the parent, which the parent could then use during its render method.

This is somewhat different from what the OP asked for, but some people might end up here (like we did) because they wanted to create a reusable trait, and thought that a child component was a good way to do that.

joeytwiddle
  • 29,306
  • 13
  • 121
  • 110
  • There is a handy list of patterns for creating re-usable traits here: https://reactjs.org/blog/2016/07/13/mixins-considered-harmful.html#migrating-from-mixins – joeytwiddle Oct 22 '18 at 08:57
7

The logic is simple.

Create a function in parent using child or use ref.

I prefer the creating function in parent using child. There are multiple ways to do it.

When using functional components

In Parent

function Parent(){
  const [functionToCall, createFunctionToCall] = useState(()=>()=>{})

  return (
   <Child createFunctionToCall={createFunctionToCall} />
  )
}

In Child

function Child({createFunctionToCall}){
  useEffect(()=>{
    function theFunctionToCall(){
      // do something like setting something
      // don't forget to set dependancies properly.
    }
    createFunctionToCall(()=>theFunctionToCall)
  },[createFunctionToCall])
}

Haseeb A
  • 5,356
  • 1
  • 30
  • 34
6

This pattern is similar to @brickingup answer. But in this version you can set as many child actions you want.

import { useEffect } from "react";

export const Parent = () => {
  const childEvents = { click: () => {} };

  return (
    <div onClick={() => childEvents.click()}>
      <Child events={childEvents}></Child>
    </div>
  );
};

export const Child = (props) => {
  const click = () => {
    alert("click from child");
  };

  useEffect(() => {
    if (props.events) {
      props.events.click = click;
    }
  }, []);

  return <span>Child Component</span>;
};
AmirHossein Rezaei
  • 1,086
  • 1
  • 16
  • 20
4

We're happy with a custom hook we call useCounterKey. It just sets up a counterKey, or a key that counts up from zero. The function it returns resets the key (i.e. increment). (I believe this is the most idiomatic way in React to reset a component - just bump the key.)

However this hook also works in any situation where you want to send a one-time message to the client to do something. E.g. we use it to focus a control in the child on a certain parent event - it just autofocuses anytime the key is updated. (If more props are needed they could be set prior to resetting the key so they're available when the event happens.)

This method has a bit of a learning curve b/c it's not as straightforward as a typical event handler, but it seems the most idiomatic way to handle this in React that we've found (since keys already function this way). Def open to feedback on this method but it is working well!

// Main helper hook:
export function useCounterKey() {
  const [key, setKey] = useState(0);
  return [key, () => setKey(prev => prev + 1)] as const;
}

Sample usages:

// Sample 1 - normal React, just reset a control by changing Key on demand
function Sample1() {
  const [inputLineCounterKey, resetInputLine] = useCounterKey();

  return <>
    <InputLine key={inputLineCounterKey} />
    <button onClick={() => resetInputLine()} />
  <>;
}

// Second sample - anytime the counterKey is incremented, child calls focus() on the input
function Sample2() {
  const [amountFocusCounterKey, focusAmountInput] = useCounterKey();

  // ... call focusAmountInput in some hook or event handler as needed

  return <WorkoutAmountInput focusCounterKey={amountFocusCounterKey} />
}

function WorkoutAmountInput(props) {
  useEffect(() => {
    if (counterKey > 0) {
      // Don't focus initially
      focusAmount();
    }
  }, [counterKey]);

  // ...
}

(Credit to Kent Dodds for the counterKey concept.)

Freewalker
  • 6,329
  • 4
  • 51
  • 70
4

Parent component

import Child from './Child'

export default function Parent(props) {
    const [childRefreshFunction, setChildRefreshFunction] = useState(null);

    return (
        <div>
            <button type="button" onClick={() => {
                childRefreshFunction();
            }}>Refresh child</button>
            <Child setRefreshFunction={(f) => {
                setChildRefreshFunction(f);
            }} />
        </div>
    )
}

Child component

export default function Child(props) {

    useEffect(() => {
        props.setRefreshFunction(() => refreshMe);
    }, []);

    function refreshMe() {
        fetch('http://example.com/data.json')....
    };

    return (
        <div>
            child
        </div>
    )
}
Lukáš Novák
  • 199
  • 1
  • 7
  • 2
    I didn't realise one could do this. Is this somehow worse than useRef or maybe not a "correct" way of doing it? I only ask as I really like this solution and I don't understand why no one else has suggested it to me. – Oliver Brace Nov 11 '21 at 12:04
  • this worked for me. you may need to check the child's `useEffect` first `useEffect(() => { if( props.setRefreshFunction ){ props.setRefreshFunction(() => refreshMe); }, []);` otherwise, you will get `setRefreshFunction` undefined. – Mel Mar 24 '22 at 05:23
2

You can achieve this easily in this way

Steps-

  1. Create a boolean variable in the state in the parent class. Update this when you want to call a function.
  2. Create a prop variable and assign the boolean variable.
  3. From the child component access that variable using props and execute the method you want by having an if condition.

    class Child extends Component {
       Method=()=>{
       --Your method body--
       }
       render() {
         return (
        //check whether the variable has been updated or not
          if(this.props.updateMethod){
            this.Method();
          }
         )
       }
    }
    
    class Parent extends Component {
    
    constructor(){
      this.state={
       callMethod:false
      }
    
    }
    render() {
       return (
    
         //update state according to your requirement
         this.setState({
            callMethod:true
         }}
         <Child updateMethod={this.state.callMethod}></Child>
        );
       }
    }
    
Kusal Kithmal
  • 1,255
  • 1
  • 10
  • 25
  • You might want to sandbox this. It looks like you're going to end up with an infinite loop because child method will continually run because parent state is set to true. – Isaac Pak Jun 03 '19 at 13:57
  • @IsaacPak Yeah, that's why I left a comment there, saying you must update the state according to your requirement. Then it won't run as an infinite loop. – Kusal Kithmal Jun 04 '19 at 03:39
2

Another way of triggering a child function from parent is to make use of the componentDidUpdate function in child Component. I pass a prop triggerChildFunc from Parent to Child, which initially is null. The value changes to a function when the button is clicked and Child notice that change in componentDidUpdate and calls its own internal function.

Since prop triggerChildFunc changes to a function, we also get a callback to the Parent. If Parent don't need to know when the function is called the value triggerChildFunc could for example change from null to true instead.

const { Component } = React;
const { render } = ReactDOM;

class Parent extends Component {
  state = {
    triggerFunc: null
  }

  render() {
    return (
      <div>
        <Child triggerChildFunc={this.state.triggerFunc} />
        <button onClick={() => {
          this.setState({ triggerFunc: () => alert('Callback in parent')})
        }}>Click
        </button>
      </div>
    );
  }
}

class Child extends Component {
  componentDidUpdate(prevProps) {
    if (this.props.triggerChildFunc !== prevProps.triggerChildFunc) {
      this.onParentTrigger();
    }
  }

  onParentTrigger() {
    alert('parent triggered me');

    // Let's call the passed variable from parent if it's a function
    if (this.props.triggerChildFunc && {}.toString.call(this.props.triggerChildFunc) === '[object Function]') {
      this.props.triggerChildFunc();
    }
  }

  render() {
    return (
      <h1>Hello</h1>
    );
  }
}


render(
  <Parent />,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='app'></div>

CodePen: https://codepen.io/calsal/pen/NWPxbJv?editors=1010

Calsal
  • 1,375
  • 14
  • 25
2

Here my demo: https://stackblitz.com/edit/react-dgz1ee?file=styles.css

I am using useEffect to call the children component's methods. I have tried with Proxy and Setter_Getter but sor far useEffect seems to be the more convenient way to call a child method from parent. To use Proxy and Setter_Getter it seems there is some subtlety to overcome first, because the element firstly rendered is an objectLike's element through the ref.current return => <div/>'s specificity. Concerning useEffect, you can also leverage on this approach to set the parent's state depending on what you want to do with the children.

In the demo's link I have provided, you will find my full ReactJS' code with my draftwork inside's so you can appreciate the workflow of my solution.

Here I am providing you my ReactJS' snippet with the relevant code only. :

import React, {
  Component,
  createRef,
  forwardRef,
  useState,
  useEffect
} from "react"; 

{...}

// Child component
// I am defining here a forwardRef's element to get the Child's methods from the parent
// through the ref's element.
let Child = forwardRef((props, ref) => {
  // I am fetching the parent's method here
  // that allows me to connect the parent and the child's components
  let { validateChildren } = props;
  // I am initializing the state of the children
  // good if we can even leverage on the functional children's state
  let initialState = {
    one: "hello world",
    two: () => {
      console.log("I am accessing child method from parent :].");
      return "child method achieve";
    }
  };
  // useState initialization
  const [componentState, setComponentState] = useState(initialState);
  // useEffect will allow me to communicate with the parent
  // through a lifecycle data flow
  useEffect(() => {
    ref.current = { componentState };
    validateChildren(ref.current.componentState.two);
  });

{...}

});

{...}

// Parent component
class App extends Component {
  // initialize the ref inside the constructor element
  constructor(props) {
    super(props);
    this.childRef = createRef();
  }

  // I am implementing a parent's method
  // in child useEffect's method
  validateChildren = childrenMethod => {
    // access children method from parent
    childrenMethod();
    // or signaling children is ready
    console.log("children active");
  };

{...}
render(){
       return (
          {
            // I am referencing the children
            // also I am implementing the parent logic connector's function
            // in the child, here => this.validateChildren's function
          }
          <Child ref={this.childRef} validateChildren={this.validateChildren} />
        </div>
       )
}
Webwoman
  • 10,196
  • 12
  • 43
  • 87
2

You can apply that logic very easily using your child component as a react custom hook.

How to implement it?

  • Your child returns a function.

  • Your child returns a JSON: {function, HTML, or other values} as the example.

In the example doesn't make sense to apply this logic but it is easy to see:

const {useState} = React;

//Parent
const Parent = () => {
  //custome hook
  const child = useChild();

  return (
    <div>
      {child.display}          
      <button onClick={child.alert}>
        Parent call child
      </button>
      {child.btn}
    </div>
  );
};

//Child
const useChild = () => {

  const [clickCount, setClick] = React.useState(0);
  
  {/* child button*/} 
  const btn = (
    <button
      onClick={() => {
        setClick(clickCount + 1);
      }}
    >
      Click me
    </button>
  );

  return {
    btn: btn,
    //function called from parent 
    alert: () => {
      alert("You clicked " + clickCount + " times");
    },
    display: <h1>{clickCount}</h1>
  };
};

const rootElement = document.getElementById("root");
ReactDOM.render(<Parent />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Bruno Pop
  • 74
  • 3
2

I tried using createRef or useRef. Somehow they all return null.

Secondly, this answer proposes to pass a prop that sets a function that seems the most reasonable to me. But if your child component is used in multiple places, you should add that extra prop to other places. Also if you want to call a method in the grandchild, this method might be too verbose or mouthful.

So I made my own function store in a very primitive way.

Below is functionStore.js file

const fns = {};

export function setFn(componentName, fnName, fn) {
  if (fns[componentName]) {
    fns[componentName][fnName] = fn;
  } else {
    fns[componentName] = { fnName: fn };
  }
}

export function callFn(componentName, fnName) {
  fns[componentName][fnName]();
}

I just set the functions that need to be called from any component.

import { setFn } from "./functionStore";
export class AComponent extends React.Component {
  componentDidMount() {
    setFn("AComponent", "aFunc", this.aFunc);
  }
  aFunc = () => { console.log("aFunc is called!"); };
}

Then I just call it from some other component

import { callFn } from "./functionStore";
export class BComponent extends React.Component {
  
  // just call the function
  bFunc = () => { 
    callFn("AComponent", "aFunc");
  };
}

One disadvantage is the function to be called should be parameterless. But this might be fixed somehow as well. Currently, I don't need to pass parameters.

canbax
  • 3,432
  • 1
  • 27
  • 44
1

I think that the most basic way to call methods is by setting a request on the child component. Then as soon as the child handles the request, it calls a callback method to reset the request.

The reset mechanism is necessary to be able to send the same request multiple times after each other.

In parent component

In the render method of the parent:

const { request } = this.state;
return (<Child request={request} onRequestHandled={()->resetRequest()}/>);

The parent needs 2 methods, to communicate with its child in 2 directions.

sendRequest() {
  const request = { param: "value" };
  this.setState({ request });
}

resetRequest() {
  const request = null;
  this.setState({ request });
}

In child component

The child updates its internal state, copying the request from the props.

constructor(props) {
  super(props);
  const { request } = props;
  this.state = { request };
}

static getDerivedStateFromProps(props, state) {
  const { request } = props;
  if (request !== state.request ) return { request };
  return null;
}

Then finally it handles the request, and sends the reset to the parent:

componentDidMount() {
  const { request } = this.state;
  // todo handle request.

  const { onRequestHandled } = this.props;
  if (onRequestHandled != null) onRequestHandled();
}
bvdb
  • 22,839
  • 10
  • 110
  • 123
0

Here's a bug? to look out for: I concur with rossipedia's solution using forwardRef, useRef, useImperativeHandle

There's some misinformation online that says refs can only be created from React Class components, but you can indeed use Function Components if you use the aforementioned hooks above. A note, the hooks only worked for me after I changed the file to not use withRouter() when exporting the component. I.e. a change from

export default withRouter(TableConfig);

to instead be

export default TableConfig;

In hindsight the withRouter() is not needed for such a component anyway, but usually it doesn't hurt anything having it in. My use case is that I created a component to create a Table to handle the viewing and editing of config values, and I wanted to be able to tell this Child component to reset it's state values whenever the Parent form's Reset button was hit. UseRef() wouldn't properly get the ref or ref.current (kept on getting null) until I removed withRouter() from the file containing my child component TableConfig

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
DeltaPng
  • 505
  • 4
  • 6