Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call child method from parent

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.

like image 208
N8FURY Avatar asked Jun 21 '16 16:06

N8FURY


People also ask

How do you call a child component method from parent in Salesforce?

Step 1) Create Child component with Aura:Method. Step 2) Create Child Class Controller to Get argument "event. getParam('arguments');" and return the message. Step 3) Create a parent Component and a button to call Aura method.


2 Answers

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 (>= [email protected])

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>
like image 133
rossipedia Avatar answered Oct 05 '22 23:10

rossipedia


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.

like image 24
brickingup Avatar answered Oct 05 '22 23:10

brickingup