React---refs

Refs提供了一個訪問render()方法內(nèi)DOM節(jié)點或者ReactNode的方法

典型的React數(shù)據(jù)流中,props是父組件和子組件交互的唯一手段。要修改一個子組件,就需要使用新的props重新渲染它。然而,確實存在少數(shù)一些情況需要命令性地(imperatively)修改一個子節(jié)點而不是通過典型的props數(shù)據(jù)流方式。被修改的子節(jié)點可能是一個React組件實例(比如調(diào)用某個子組件的實例方法),亦或是一個DOM元素(比如手動地控制某個input標(biāo)簽聚焦)。對于這兩種情況,React都提供了各種處理方法,refs就是其中的一種。

1. refs適用的場景

  • 手動控制DOM節(jié)點
  • 獲取子組件的尺寸或者實例方法
  • 和第三方DOM庫集成(典型的jPlayer)

注意:不要濫用refs,比如:在使用antd的<Modal />時,可以直接通過修改props.visible為true或false即可實現(xiàn)Modal組件的顯示和隱藏,則大可不必使用該組件的show()、hide()方法

2. 創(chuàng)建Refs

注意:Ract 16.3引入的API React.createRef()。比較舊的React版本,保留了refs關(guān)鍵字。不管是新舊版本,都建議使用refs回調(diào)方式(最后的有對應(yīng)的示例)。本文主要實現(xiàn)一個頁面加載時,Input組件自動聚焦,并且在點擊Button組件時聚焦Input組件的功能,使用的方法為React.createRef()。github代碼庫中有對應(yīng)的新舊版本實現(xiàn)方式。

  1. refs通過React.createRef()創(chuàng)建,使屬性ref附加到React元素上。Refs通常在 一個組件構(gòu)造時賦值給一個實例屬性,這樣在整個組件中他們都可以被引用到。
  2. 創(chuàng)建以后,通過React.createRef().current方法獲取。

根據(jù)節(jié)點類型的不同,ref的值也不同:

  • 如果ref用在HTML元素上,構(gòu)造函數(shù)中通過React.createRef()創(chuàng)建的ref會將原生DOM元素放到它的current屬性中。
  • 如果ref用在自定義組件類型上,ref使用它的current屬性指向所掛載的組件實例。
  • 函數(shù)式組件上不能使用ref,因為它們沒有實例。

3. DOM中創(chuàng)建與使用

class Input extends React.Component {
    constructor(props) {
        super(props)
        // 在構(gòu)造方法內(nèi)初始化
        this.inputRef = React.createRef()
    }

    componentDidMount() {
        // 使用.current調(diào)用
        this.inputRef.current.focus();
    }
    
    // Input的實例方法
    focus = () => {
        if(this.inputRef.current) this.inputRef.current.focus();
    }

    render() {
        return (
            <div className="block">
                <p>Input 加載時自動聚焦</p>
                <input ref={this.inputRef} />
            </div>
        )
    }
}

組件掛載時,React會將ref的current屬性設(shè)置成DOM元素,卸載時,再把ref的current屬性設(shè)置為null。ref更新發(fā)生在componentDidMount或者componentDidUpdate生命周期回調(diào)之前。

4. 自定義組件中創(chuàng)建與使用

import React from 'react'
import Button from './Button'
import Input from './Input'

class Ref extends React.Component {
    constructor(props) {
        super(props)
        // 初始化 獲取掛載的組件Input實例
        this.inputComponentRef = React.createRef()
    }

    
    handleClick = () => {
        // 調(diào)用Input實例的方法
        if(this.inputComponentRef.current) this.inputComponentRef.current.focus()
    }

    render() {
        return (
            <div>
                <Button onClick={this.handleClick} />
                <Input ref={this.inputComponentRef} />
            </div>
        )
    }
}

export default Ref

同DOM中使用類似,組件掛載時,React會將ref的current屬性設(shè)置成組件的實例,卸載時,再把ref的current屬性設(shè)置為null。ref更新發(fā)生在componentDidMount或者componentDidUpdate生命周期回調(diào)之前。

5. 函數(shù)式組件無法為當(dāng)前組件直接創(chuàng)建refs

const Input = () => <input />

class App extends React.Component {
  constructor(props) {
    super(props);
    this.inputComponentRef = React.createRef();
  }
  
  render() {
    // 不起作用,會報錯
    return (
      <Input ref={this.inputComponentRef} />
    );
  }
}

但是,函數(shù)式組件內(nèi)部可以使用ref引用屬性使其指向一個DOM元素或者一個類組件,例如:

const Input = (props) => {
    let inputRef = React.createRef();

    function handleClick() {
      inputRef.current.focus();
    }

    return (
      <div>
        <input
         type="text"
          ref={inputRef} />

        <button
          onClick={handleClick}
        >Focus</button>
      </div>
    )
}

6. 使用回調(diào)的方式 (推薦)

在需要聲明ref的位置綁定一個方法,返回的參數(shù)是DOM節(jié)點或則實例組件,組件在加載時會自動觸發(fā)該回調(diào)方法,該參數(shù)作為實例的一個屬性在其他位置直接使用即可。


class Input extends React.Component {
    constructor(props) {
        super(props)
    }

    componentDidMount() {
        // 不需要使用current調(diào)用
        this.inputRef && this.inputRef.focus();
    }

    initRef = (ele) => {
        // 組件加載時(或者更新時)自動觸發(fā)該方法
        this.inputRef = ele
    }
    
    focus = () => {
        if(this.inputRef) this.inputRef.focus();
    }

    
    render() {
        return (
            <div className="block">
                <p>Input 加載時自動聚焦</p>
                <input ref={this.initRef} />
            </div>
        )
    }
}

export default Input

使用引用回調(diào)函數(shù)的注意事項
如果ref回調(diào)函數(shù)定義在內(nèi)聯(lián)函數(shù)(inline function)中,更新時他會被調(diào)用兩次,第一次參數(shù)是null,第二次參數(shù)才是DOM元素。這是因為每個渲染都會創(chuàng)建一個新的函數(shù)實例,所以React需要清除舊的引用并設(shè)置新的。你可以通過將引用回調(diào)定義為該類的綁定方法來避免這種情況,但請注意,大多數(shù)情況下這樣做或者不這樣做都沒太大關(guān)系。

7. React低版本遺留的API:字符串引用Refs

綁定一個 字符串類型的ref 屬性到 render 的返回值上

<input ref="myInput" />

在其他位置(實例方法或者生命周期函數(shù)中)使用

componentDidMount() {
  // 保留關(guān)鍵字this.refs
  // 頁面加載完成時使input標(biāo)簽自動聚焦
  this.refs.myInput.focus()
}

8. 建議使用其他的解決方案替代refs

在極少的一些情況下,我們需要從父組件中訪問某個子DOM節(jié)點或者子組件的一些屬性和方法。一般來說不建議這么做,因為它打破了組件封裝,但是它偶爾也很有用,比如觸發(fā)獲取焦點,或者測量一個子DOM節(jié)點的尺寸或者位置。
本文代碼鏈接地址:https://github.com/zhiyuanMain/ReactForJianshu.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • refs提供了可以在render方法中訪問dom節(jié)點和創(chuàng)建的react元素的方法。 為了良好的閱讀體驗,請查看gi...
    mytac閱讀 514評論 0 1
  • ? 在常規(guī)的 React 數(shù)據(jù)六中,props 是父組件與子組件交互的唯一方法。如果需要改子元素,你需要用新的pr...
    果汁涼茶丶閱讀 1,033評論 0 0
  • It's a common pattern in React to wrap a component in an ...
    jplyue閱讀 3,401評論 0 2
  • 有效的人生,無法違背的傾向性,在倫理道德法律范圍內(nèi)爭取做更多,只有這輩子更好的自己,下輩子循環(huán)反復(fù)……
    心安_913c閱讀 408評論 0 0
  • 2018年6月3日 星期日 天晴 文|墨涼 圖|網(wǎng)絡(luò) 我輕輕的告訴你,你今天真好看! 喂!你昨晚是失眠...
    十翰墨涼閱讀 2,870評論 9 11

友情鏈接更多精彩內(nèi)容