【问题标题】:Maintaining Component Refs Through React.cloneElement通过 React.cloneElement 维护组件 Refs
【发布时间】:2017-06-12 02:46:28
【问题描述】:

我一直在测试使用React.cloneElement() 扩展组件的children 可能存在的限制/危险。我发现的一种可能的危险是可能会覆盖 refkey 等道具。

但是,根据 React 的 0.13 release candidate(早在 2015 年):

但是,与 JSX 和 cloneWithProps 不同的是,它还保留了 refs。这意味着如果你得到一个带有 ref 的孩子,你不会不小心从你的祖先那里偷走它。您将获得附加到新元素的相同 ref。

[...]

注意:React.cloneElement(child, { ref: 'newRef' }) 确实会覆盖 ref,因此两个父母仍然不可能拥有同一个孩子的 ref,除非您使用 callback-refs。

我写了一个small React application,它克隆了被推送的子组件,在两个级别上测试了引用的有效性:

class ChildComponent extends React.Component{
  constructor(props){
    super(props);   
  
    this.onClick = this.onClick.bind(this);
    this.extendsChildren = this.extendChildren(this);
  }
  
  onClick(e) {
    e.preventDefault();
    
    try{
      alert(this._input.value);
    }catch(e){
      alert('ref broken :(');
    }
  }
  
  extendChildren(){
    return React.Children.map(this.props.children, child => {
      return React.cloneElement(
        child,
        {
          ref: ref => this._input = ref
        }
      );
    });
  }
  
  render() {
    return(
      <div>
      <button onClick={this.onClick}>
        ChildComponent ref check
      </button>
      {this.extendChildren()}
    </div>
    );
  }
}


class AncestorComponent extends React.Component{
  constructor(props){
    super(props);
    
    this.onClick = this.onClick.bind(this);
  }
  
  onClick(e) {
    e.preventDefault();
    
    try{
      alert(this._input.value);
    }catch(e){
      alert('ref broken :(');
    }
    
  }
  
  render() {
    return (
    <div>
        <p>
          The expected behaviour is that I should be able to click on both Application and ChildComponent check buttons and have a reference to the input (poping an alert with the input's value).
        </p>
      <button onClick={this.onClick}>
        Ancestor ref check
      </button>
      <ChildComponent>
        <input ref={ref => this._input = ref} defaultValue="Hello World"/>
      </ChildComponent>
    </div>
    );
  }
}

但是,我的 ChildComponent 中的 cloningElements 会覆盖来自输入字段的 AncestorComponent 的 ref 属性,我希望在其中保留 ref 属性,以及我定义为 React.cloneElement 的一部分的新 ref

您可以通过运行 CodePen 进行测试。

是我做错了什么,还是从那以后这个功能被删除了?

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    根据 Dan Abramov 的 response,覆盖引用,即使有回调,仍然会覆盖引用。您需要在回调声明中调用当前引用:

    return React.Children.map(this.props.children, child =>
      React.cloneElement(child, {
        ref(node) {
          // Keep your own reference
          this._input = node;
          // Call the original ref, if any
          const {ref} = child;
          if (typeof ref === 'function') {
            ref(node);
          }
        }
      )
    );
    

    【讨论】:

      猜你喜欢
      • 2019-07-03
      • 2018-11-24
      • 1970-01-01
      • 1970-01-01
      • 2016-08-10
      • 1970-01-01
      • 2019-12-05
      • 1970-01-01
      • 2013-02-04
      相关资源
      最近更新 更多