React中refs的理解

React中refs的理解

Refs提供了一種方式,容許咱們訪問DOM節點或在render方法中建立的React元素。html

描述

在典型的React數據流中,props是父組件與子組件交互的惟一方式,要修改一個子組件,你須要使用新的props來從新渲染它,可是在某些狀況下,你須要在典型數據流以外強制修改子組件,被修改的子組件多是一個React組件的實例,也多是一個DOM元素,對於這兩種狀況React都提供瞭解決辦法。
避免使用refs來作任何能夠經過聲明式實現來完成的事情,一般在能夠使用propsstate的狀況下勿依賴refs,下面是幾個適合使用refs的狀況:react

  • 管理焦點、文本選擇或媒體播放。
  • 觸發強制動畫。
  • 集成第三方DOM庫。

使用

React提供的這個ref屬性,表示爲對組件真正實例的引用,其實就是ReactDOM.render()返回的組件實例,須要區分一下渲染組件與渲染原生DOM元素,渲染組件時返回的是組件實例,而渲染DOM元素時,返回是具體的DOM節點,Reactref3種用法。git

字符串

ref能夠直接設置爲字符串值,這種方式基本不推薦使用,或者在將來的React版本中不會再支持該方式。這主要是由於使用字符串致使的一些問題,例如當ref定義爲string時,須要React追蹤當前正在渲染的組件,在reconciliation階段,React Element建立和更新的過程當中,ref會被封裝爲一個閉包函數,等待commit階段被執行,這會對React的性能產生一些影響等。github

class InputOne extends React.Component {
    componentDidMount() {
        this.refs.inputRef.value = 1;
      }
    render() {
        return <input ref="inputRef" />;
    }
}

回調

React支持給任意組件添加特殊屬性,ref屬性接受一個回調函數,其在組件被加載或卸載時會當即執行。segmentfault

  • 當給HTML元素添加ref屬性時,ref回調接收了底層的DOM元素做爲參數。
  • 當給組件添加ref屬性時,ref回調接收當前組件實例做爲參數。
  • 當組件卸載的時候,會傳入null
  • ref回調會在componentDidMountcomponentDidUpdate等生命週期回調以前執行。

Callback Ref咱們一般會使用內聯函數的形式,那麼每次渲染都會從新建立,因爲React會清理舊的ref而後設置新的,所以更新期間會調用兩次,第一次爲null,若是在Callback中帶有業務邏輯的話,可能會出錯,能夠經過將Callback定義成類成員函數並進行綁定的方式避免。api

class InputTwo extends React.Component {
    componentDidMount() {
        this.inputRef.value = 2;
      }
    render() {
        return <input ref={(element) =>this.inputRef = element} />;
    }
}

API建立

React v16.3中經0017-new-create-ref提案引入了新的React.createRefAPI,當ref被傳遞給render中的元素時,對該節點的引用能夠在refcurrent屬性中被訪問,ref的值根據節點的類型而有所不一樣:數組

  • ref屬性用於HTML元素時,構造函數中使用React.createRef()建立的ref接收底層DOM元素做爲其current屬性。
  • ref屬性用於自定義class組件時,ref對象接收組件的掛載實例做爲其current屬性。
  • 不能在函數組件上使用ref屬性,由於他們沒有實例。

對比新的CreateRefCallback Ref,並無壓倒性的優點,只是但願成爲一個便捷的特性,在性能上會會有微小的優點,Callback Ref採用了組件Render過程當中在閉包函數中分配ref的模式,而CreateRef則採用了Object Refbabel

class InputThree extends React.Component {
    constructor(props) {
        super(props);
        this.inputRef = React.createRef();
    }
    componentDidMount() {
        this.inputRef.current.value = 3;
    }
    render() {
        return <input ref={this.inputRef} />;
    }
}

示例

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>React</title>
</head>

<body>
    <div id="root"></div>
</body>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
    class InputOne extends React.Component {
        componentDidMount() {
            this.refs.inputRef.value = 1;
          }
        render() {
            return <input ref="inputRef" />;
        }
    }

    class InputTwo extends React.Component {
        componentDidMount() {
            this.inputRef.value = 2;
          }
        render() {
            return <input ref={(element) =>this.inputRef = element} />;
        }
    }

    class InputThree extends React.Component {
        constructor(props) {
            super(props);
            this.inputRef = React.createRef();
        }
        componentDidMount() {
            this.inputRef.current.value = 3;
        }
        render() {
            return <input ref={this.inputRef} />;
        }
    }
    

    var vm = ReactDOM.render(
        <>
            <InputOne />
            <InputTwo />
            <InputThree />
        </>,
        document.getElementById("root")
    );
</script>

</html>

每日一題

https://github.com/WindrunnerMax/EveryDay

參考

https://zhuanlan.zhihu.com/p/40462264
https://www.jianshu.com/p/4e2357ea1ba1
https://juejin.cn/post/6844903809274085389
https://juejin.cn/post/6844904048882106375
https://segmentfault.com/a/1190000008665915
https://zh-hans.reactjs.org/docs/refs-and-the-dom.html
相關文章
相關標籤/搜索