React---refs

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

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

1. refs適用的場景

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

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

2. 創(chuàng)建Refs

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

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

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

  • 如果ref用在HTML元素上,構(gòu)造函數(shù)中通過React.createRef()創(chuàng)建的ref會(huì)將原生DOM元素放到它的current屬性中。
  • 如果ref用在自定義組件類型上俏讹,ref使用它的current屬性指向所掛載的組件實(shí)例当宴。
  • 函數(shù)式組件上不能使用ref,因?yàn)樗鼈儧]有實(shí)例。

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的實(shí)例方法
    focus = () => {
        if(this.inputRef.current) this.inputRef.current.focus();
    }

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

組件掛載時(shí)泽疆,React會(huì)將ref的current屬性設(shè)置成DOM元素户矢,卸載時(shí),再把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實(shí)例
        this.inputComponentRef = React.createRef()
    }

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

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

export default Ref

同DOM中使用類似,組件掛載時(shí)株依,React會(huì)將ref的current屬性設(shè)置成組件的實(shí)例驱证,卸載時(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() {
    // 不起作用,會(huì)報(bào)錯(cuò)
    return (
      <Input ref={this.inputComponentRef} />
    );
  }
}

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

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的位置綁定一個(gè)方法,返回的參數(shù)是DOM節(jié)點(diǎn)或則實(shí)例組件哈肖,組件在加載時(shí)會(huì)自動(dòng)觸發(fā)該回調(diào)方法吻育,該參數(shù)作為實(shí)例的一個(gè)屬性在其他位置直接使用即可。


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

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

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

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

export default Input

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

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

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

<input ref="myInput" />

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

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

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

在極少的一些情況下,我們需要從父組件中訪問某個(gè)子DOM節(jié)點(diǎn)或者子組件的一些屬性和方法止吐。一般來說不建議這么做宝踪,因?yàn)樗蚱屏私M件封裝,但是它偶爾也很有用祟印,比如觸發(fā)獲取焦點(diǎn)肴沫,或者測量一個(gè)子DOM節(jié)點(diǎn)的尺寸或者位置。
本文代碼鏈接地址:https://github.com/zhiyuanMain/ReactForJianshu.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蕴忆,一起剝皮案震驚了整個(gè)濱河市颤芬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖站蝠,帶你破解...
    沈念sama閱讀 212,294評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汰具,死亡現(xiàn)場離奇詭異,居然都是意外死亡菱魔,警方通過查閱死者的電腦和手機(jī)留荔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來澜倦,“玉大人聚蝶,你說我怎么就攤上這事≡逯危” “怎么了碘勉?”我有些...
    開封第一講書人閱讀 157,790評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長桩卵。 經(jīng)常有香客問我验靡,道長,這世上最難降的妖魔是什么雏节? 我笑而不...
    開封第一講書人閱讀 56,595評(píng)論 1 284
  • 正文 為了忘掉前任胜嗓,我火速辦了婚禮,結(jié)果婚禮上钩乍,老公的妹妹穿的比我還像新娘辞州。我一直安慰自己,他們只是感情好寥粹,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,718評(píng)論 6 386
  • 文/花漫 我一把揭開白布孙技。 她就那樣靜靜地躺著,像睡著了一般排作。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上亚情,一...
    開封第一講書人閱讀 49,906評(píng)論 1 290
  • 那天妄痪,我揣著相機(jī)與錄音,去河邊找鬼楞件。 笑死衫生,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的土浸。 我是一名探鬼主播罪针,決...
    沈念sama閱讀 39,053評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼黄伊!你這毒婦竟也來了泪酱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,797評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎墓阀,沒想到半個(gè)月后毡惜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,250評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斯撮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,570評(píng)論 2 327
  • 正文 我和宋清朗相戀三年经伙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勿锅。...
    茶點(diǎn)故事閱讀 38,711評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡帕膜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出溢十,到底是詐尸還是另有隱情垮刹,我是刑警寧澤,帶...
    沈念sama閱讀 34,388評(píng)論 4 332
  • 正文 年R本政府宣布茶宵,位于F島的核電站危纫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏乌庶。R本人自食惡果不足惜种蝶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,018評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瞒大。 院中可真熱鬧螃征,春花似錦、人聲如沸透敌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,796評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽酗电。三九已至魄藕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撵术,已是汗流浹背背率。 一陣腳步聲響...
    開封第一講書人閱讀 32,023評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嫩与,地道東北人寝姿。 一個(gè)月前我還...
    沈念sama閱讀 46,461評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像划滋,于是被迫代替她去往敵國和親饵筑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,595評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

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