React Parent Component Calling Child Component Methods

Class component
React.createRef()


Advantages: Easy to understand, using ref to point.


Disadvantages: Not available for child components wrapped with HOC, cannot point to the real child component.
For example, some common patterns like child components wrapped with @observer from mobx are not applicable with this method.


import React, { Component } from 'react';

class Sub extends Component {
  callback() {
    console.log('Execute callback');
  }
  render() {
    return <div>Child Component</div>;
  }
}

class Super extends Component {
  constructor(props) {
    super(props);
    this.sub = React.createRef();
  }
  handleOnClick() {
    this.sub.callback();
  }
  render() {
    return (
      <div>
        <Sub ref={this.sub}></Sub>
      </div>
    );
  }
}

Copy code
Functional ref declaration

Advantages: Concise ref syntax
Disadvantages: Not available for child components wrapped with HOC, cannot point to the real child component (same as above)

Usage is similar to the above, but the way to define ref is different.
...

<Sub ref={ref => this.sub = ref}></Sub>

...

Copy code
Using custom onRef prop via props

Advantages: If the child component is nested with HOC, it can still point to the real child component.
Disadvantages: Requires custom props attribute

import React, { Component } from 'react';
import { observer } from 'mobx-react'

@observer
class Sub extends Component {
    componentDidMount(){
    // Point the child component to the parent component's variable
        this.props.onRef && this.props.onRef(this);
    }
    callback(){
        console.log("Execute me")
    }
    render(){
        return (<div>Child Component</div>);
    }
}

class Super extends Component {
    handleOnClick(){
       // Can call child component method
        this.Sub.callback();
    }
    render(){
        return (
          <div>
            <div onClick={this.handleOnClick}>click</div>
            <Sub onRef={ node => this.Sub = node }></Sub>	
       	  </div>)
    }
}

Copy code
Function component, Hook component
useImperativeHandle

Advantages:
1. Simple and easy to understand
2. If the child component is nested with HOC, it can still point to the real child component
Disadvantages:
1. Requires custom props attribute
2. Requires custom exposed methods

import React, { useImperativeHandle } from 'react';
import { observer } from 'mobx-react'


const Parent = () => {
  let ChildRef = React.createRef();

  function handleOnClick() {
    ChildRef.current.func();
  }

  return (
    <div>
      <button onClick={handleOnClick}>click</button>
      <Child onRef={ChildRef} />
    </div>
  );
};

const Child = observer(props => {
  // Use useImperativeHandle to expose some properties that external ref can access
  useImperativeHandle(props.onRef, () => {
    // Need to return the exposed interface
    return {
      func: func,
    };
  });
  function func() {
    console.log('Execute me');
  }
  return <div>Child Component</div>;
});

export default Parent;
Copy code
forwardRef
Using forwardRef to expose the child component's ref
This method is actually more suitable for custom HOCs. However, the problem is that methods like withRouter, connect, Form.create cannot expose refs. If the child itself needs to be nested with these methods, it basically cannot be used together. forwardRef itself is used to expose refs of child elements like native elements (e.g., input), and is not suitable for exposing component refs because component usage scenarios are too complex.
import React, { useRef, useImperativeHandle } from 'react';
import ReactDOM from 'react-dom';
import { observer } from 'mobx-react'

const FancyInput = React.forwardRef((props, ref) => {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));

  return <input ref={inputRef} type="text" />
});

const Sub = observer(FancyInput)

const App = props => {
  const fancyInputRef = useRef();

  return (
    <div>
      <FancyInput ref={fancyInputRef} />
      <button
        onClick={() => fancyInputRef.current.focus()}
      >Parent component calls child component's focus</button>
    </div>
  )
}

export default App;

评论

暂无评论。

登录后可发表评论。