更多的關(guān)于Refs

2019-08-14 14:28 更新

從你的 render 方法中返回你的 UI 結(jié)構(gòu)后,你會(huì)發(fā)現(xiàn)你想要“伸手”調(diào)用從 render 返回的組件實(shí)例的方法。通常來(lái)說(shuō),這樣做對(duì)于通過(guò)你的應(yīng)用程序制作數(shù)據(jù)流是沒(méi)有必要的,因?yàn)?Reactive 數(shù)據(jù)流總是確保最新的 props 被發(fā)送到由 render() 輸出的每個(gè)孩子中。但是在一些情況下,它仍然有可能是必要或有益的。

考慮這樣一種情況,當(dāng)你在把一個(gè) <input / > 元素(存在于你的實(shí)例 sub-hierarchy 中)的值更新為一個(gè)空字符串后 ,想告訴它聚焦。

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>
      );
    }
  });

注意,在本例中,我們想要“告訴”輸入一些東西——這些東西是它不能從道具中推斷出的。在這個(gè)例子中,我們想要“告訴”它,現(xiàn)在它應(yīng)該聚焦。然而,也有一些挑戰(zhàn)。從 render() 返回的不是你 “子”組件的實(shí)際組成,它僅僅是在一個(gè)特定的實(shí)例中的子組件的描述——如果你愿意的話可以是一個(gè)快照。

注意:

記住,從 render() 返回來(lái)的不是你實(shí)際繪制的子組件的實(shí)例。從 render() 返回來(lái)的僅僅是一個(gè)特定的時(shí)刻在你組成部分的 sub-hierarchy 中的子組件實(shí)例的描述。

這意味著你不應(yīng)該“持有”從 render() 返回來(lái)的東西,并且指望它有任何的意義。

// 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>
    );
  }

在這個(gè)反例中,<input/ > 僅僅是 <input/ > 的描述。這個(gè)描述是用來(lái)為 <input/ > 創(chuàng)建一個(gè)真正的 支持實(shí)例。

那么, 我們?cè)趺丛L問(wèn) input的 真正的 支持實(shí)例呢?

Ref 的字符串屬性

React 支持一個(gè)非常特殊的屬性,你可以附加到任何從 render() 輸出的組件中。這個(gè)特殊的屬性允許你涉及相應(yīng)的任何從 render() 返回的支持實(shí)例。它總是保證成為適當(dāng)?shù)膶?shí)例,在任何時(shí)候。

這個(gè)非常簡(jiǎn)單:

  1. 給從 render 返回的東西分配 ref 屬性,如:

<input ref="myInput" />
  1. 在其他一些代碼(典型的是事件處理程序的代碼),通過(guò) this.refs 訪問(wèn) backing instance,如:

this.refs.myInput

你可以通過(guò)調(diào)用 React.findDOMNode(this.refs.myInput) 直接訪問(wèn)組件的 DOM 節(jié)點(diǎn)。

ref 回調(diào)屬性

ref 屬性可以是一個(gè)回調(diào)函數(shù),而不是一個(gè)名字。這個(gè)回調(diào)函數(shù)在組件安裝后立即執(zhí)行。被引用的組件作為一個(gè)參數(shù)傳遞,且回調(diào)函數(shù)可以立即使用這個(gè)組件,或保存供以后使用(或?qū)崿F(xiàn)這兩種行為)。

它與把 ref 屬性分配給從 render 返回來(lái)的東西一樣簡(jiǎn)單,如:

<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>
      );
    }
  });

在這個(gè)例子中,render 函數(shù)返回 <input/ > 實(shí)例的描述。但真正的實(shí)例是通過(guò) this.refs.theInput 訪問(wèn)的。只要帶有 ref =“theInput” 的子組件從 render 返回,this.refs.theInput 就會(huì)訪問(wèn)適當(dāng)?shù)膶?shí)例。這甚至能在更高的級(jí)別(non-DOM)組件中實(shí)現(xiàn),如 <Typeahead ref = " myTypeahead " / >。

總結(jié)

向一個(gè)特定的子實(shí)例發(fā)送消息,Refs 是一個(gè)很好的方式,而通過(guò)流動(dòng)式接收 Reactive 的 props  state 的方式可能是不方便的。然而,對(duì)于你的應(yīng)用程序中的流動(dòng)數(shù)據(jù)來(lái)說(shuō),refs 應(yīng)該不是你的首選抽象特性。默認(rèn)情況下,為用例使用 Reactive 數(shù)據(jù)流并保存 refs 本來(lái)就是無(wú)功無(wú)過(guò)的。

好處:

  • 你可以在組件類中定義任何公共方法(如在 Typeahead 中的復(fù)位方法),并通過(guò) refs(如 this.refs.myTypeahead.reset())調(diào)用這些公共方法。

  • 執(zhí)行 DOM 測(cè)量幾乎總是需要接觸“本地”組件,如 <input/ >,并通過(guò) React.findDOMNode(this.refs.myInput) 訪問(wèn)它的底層 DOM 節(jié)點(diǎn)。Refs 是可行的可靠的方法之一。

  • refs 自動(dòng)為你 book-kept!如果子組件被摧毀,那么它的 ref 也被摧毀了。在這里不必?fù)?dān)心內(nèi)存(除非你為保留自己的 reference 做了一些瘋狂的事)。

注意事項(xiàng):

  • 永遠(yuǎn)不要訪問(wèn)組件的 render 方法內(nèi)部的 refs——或任何組件的 render 方法正在 call satck 中運(yùn)行時(shí),也不要訪問(wèn) refs。

  • 如果你想保存 Google Closure Compiler Crushing 的彈性,確保永遠(yuǎn)不要訪問(wèn)作為字符串被指定的屬性。這意味著如果你的 ref 被定義為 ref =“myRefString”,你必須使用 this.refs['myRefString'] 來(lái)訪問(wèn)。

  • 如果你還沒(méi)有用 React 給幾個(gè)應(yīng)用程序編程,那么你通常首先會(huì)傾向于嘗試使用 refs 來(lái)“讓事情發(fā)生”在你的應(yīng)用程序中。如果是這樣的話,花點(diǎn)時(shí)間,更為慎重的思考一下 state 應(yīng)該屬于組件層次結(jié)構(gòu)的什么位置。通常情況下,你會(huì)清楚地發(fā)現(xiàn),“擁有”那個(gè) state 的適當(dāng)?shù)奈恢檬歉叩膶哟谓Y(jié)構(gòu)中。把 state 放置在那里通??梢韵魏蜗胍褂?span id="5w88nvj" class="Apple-converted-space"> ref 來(lái)“讓事情發(fā)生”的現(xiàn)象——相反,數(shù)據(jù)流通常會(huì)實(shí)現(xiàn)你的目標(biāo)。



以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)