简体   繁体   中英

Best practices for using React refs to call child function

I'm hoping for some clarity on the use of React refs for calling a child function. I have a Parent component that's a toolbar with a few buttons on it, and in the child component I have access to a library's export functionality. I'd like to call this export function on a button click in the parent component. Currently I'm using React refs to accomplish this:

Parent.js [ref]

class Parent extends React.Component {

  onExportClick = () => {
    this.childRef.export();
  }

  render() {
    return (
      <div>
        <button onClick={this.onExportClick} />Export</button>
        <Child ref={(node) => this.childRef = node;} />
      </div>
    )
  }
}

Child.js [ref]

class Child extends React.Component {

  export() {
    this.api.exportData();
  }

  render() {
    <ExternalLibComponent
      api={(api) => this.api = api}
    />
  }
}

This solution works fine, but I've seen a lot of disagreement on if this is the best practice. React's official doc on refs says that we should "avoid using refs for anything that can be done declaratively". In a discussion post for a similar question, Ben Alpert of the React Team says that "refs are designed for exactly this use case" but usually you should try to do it declaratively by passing a prop down.

Here's how I would do this declaratively without ref :

Parent.js [declarative]

class Parent extends React.Component {

  onExportClick = () => {
    // Set to trigger props change in child
    this.setState({
      shouldExport: true,
    });

    // Toggle back to false to ensure child doesn't keep 
    // calling export on subsequent props changes
    // ?? this doesn't seem right
    this.setState({
      shouldExport: false,
    });
  }

  render() {
    return (
      <div>
        <button onClick={this.onExportClick} />Export</button>
        <Child shouldExport={this.state.shouldExport}/>
      </div>
    )
  }
}

Child.js [declarative]

class Child extends React.Component {

  componentWillReceiveProps(nextProps) {
    if (nextProps.shouldExport) {
      this.export();
    }
  }

  export() {
    this.api.exportData();
  }

  render() {
    <ExternalLibComponent
      api={(api) => this.api = api}
    />
  }
}

Although refs are seen as an "escape hatch" for this problem, this declarative solution seems a little hacky, and not any better than using refs. Should I continue to use refs to solve this problem? Or should I go with the somewhat hacky declarative approach?

You don't need to set the shouldExport back to false , you could instead detect the change:

componentWillReceiveProps(nextProps) {
    if (nextProps.shouldExport !== this.props.shouldExport) {
        this.export();
    }
}

Then every toggle of the shouldExport would cause exactly one export. This however looks weird, I'd use a number that I'd increment:

componentWillReceiveProps(nextProps) {
    if (nextProps.exportCount > this.props.exportCount) {
        this.export();
    }
}

我现在在很多场合都遇到过同样的问题,并且由于React团队不鼓励这样做,所以我会在以后的开发中使用props方法,但是问题是有时您想将值返回给父组件,有时您需要检查孩子的状态以决定是否触发事件,因此refs方法将永远是我的最后避风港,我建议您这样做

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM