集册 React 中文版 更多的关于Refs

更多的关于Refs

欢马劈雪     最近更新时间:2020-08-04 05:37:59

368

从你的 render 方法中返回你的 UI 结构后,你会发现你想要“伸手”调用从 render 返回的组件实例的方法。通常来说,这样做对于通过你的应用程序制作数据流是没有必要的,因为 Reactive 数据流总是确保最新的 props 被发送到由 render() 输出的每个孩子中。但是在一些情况下,它仍然有可能是必要或有益的。

考虑这样一种情况,当你在把一个 <input / > 元素(存在于你的实例 sub-hierarchy 中)的值更新为一个空字符串后 ,想告诉它聚焦。

var App = React.createClass({
    getInitialState: function() {
      return {userInput: ''};
    },
    handleChange: function(e) {
      this.setState({userInput: e.target.value});
    },
    clearAndFocusInput: function() {
      this.setState({userInput: ''}); // Clear the input
      // We wish to focus the <input /> now!
    },
    render: function() {
      return (
        <div>
          <div onClick={this.clearAndFocusInput}>
            Click to Focus and Reset
          </div>
          <input
            value={this.state.userInput}
            onChange={this.handleChange}
          />
        </div>
      );
    }
  });

注意,在本例中,我们想要“告诉”输入一些东西——这些东西是它不能从道具中推断出的。在这个例子中,我们想要“告诉”它,现在它应该聚焦。然而,也有一些挑战。从 render() 返回的不是你 “子”组件的实际组成,它仅仅是在一个特定的实例中的子组件的描述——如果你愿意的话可以是一个快照。

注意:

记住,从 render() 返回来的不是你实际绘制的子组件的实例。从 render() 返回来的仅仅是一个特定的时刻在你组成部分的 sub-hierarchy 中的子组件实例的描述

这意味着你不应该“持有”从 render() 返回来的东西,并且指望它有任何的意义。

// counterexample: DO NOT DO THIS!
  render: function() {
    var myInput = <input />;          // I'm going to try to call methods on this
    this.rememberThisInput = myInput; // input at some point in the future! YAY!
    return (
      <div>
        <div>...</div>
        {myInput}
      </div>
    );
  }

在这个反例中,<input/ > 仅仅是 <input/ > 的描述。这个描述是用来为 <input/ > 创建一个真正的 支持实例

那么, 我们怎么访问 input的 真正的 支持实例呢?

Ref 的字符串属性

React 支持一个非常特殊的属性,你可以附加到任何从 render() 输出的组件中。这个特殊的属性允许你涉及相应的任何从 render() 返回的支持实例。它总是保证成为适当的实例,在任何时候。

这个非常简单:

  1. 给从 render 返回的东西分配 ref 属性,如:
<input ref="myInput" />
  1. 在其他一些代码(典型的是事件处理程序的代码),通过 this.refs 访问 backing instance,如:
this.refs.myInput

你可以通过调用 React.findDOMNode(this.refs.myInput) 直接访问组件的 DOM 节点。

ref 回调属性

ref 属性可以是一个回调函数,而不是一个名字。这个回调函数在组件安装后立即执行。被引用的组件作为一个参数传递,且回调函数可以立即使用这个组件,或保存供以后使用(或实现这两种行为)。

它与把 ref 属性分配给从 render 返回来的东西一样简单,如:

<input ref={ function(component){ React.findDOMNode(component).focus();} } />

完成的示例

var App = React.createClass({
    getInitialState: function() {
      return {userInput: ''};
    },
    handleChange: function(e) {
      this.setState({userInput: e.target.value});
    },
    clearAndFocusInput: function() {
      // Clear the input
      this.setState({userInput: ''}, function() {
        // This code executes after the component is re-rendered
        React.findDOMNode(this.refs.theInput).focus();   // Boom! Focused!
      });
    },
    render: function() {
      return (
        <div>
          <div onClick={this.clearAndFocusInput}>
            Click to Focus and Reset
          </div>
          <input
            ref="theInput"
            value={this.state.userInput}
            onChange={this.handleChange}
          />
        </div>
      );
    }
  });

在这个例子中,render 函数返回 <input/ > 实例的描述。但真正的实例是通过 this.refs.theInput 访问的。只要带有 ref =“theInput” 的子组件从 render 返回,this.refs.theInput 就会访问适当的实例。这甚至能在更高的级别(non-DOM)组件中实现,如 <Typeahead ref = " myTypeahead " / >

总结

向一个特定的子实例发送消息,Refs 是一个很好的方式,而通过流动式接收 Reactive 的 propsstate 的方式可能是不方便的。然而,对于你的应用程序中的流动数据来说,refs 应该不是你的首选抽象特性。默认情况下,为用例使用 Reactive 数据流并保存 refs 本来就是无功无过的。

好处:

展开阅读全文