Refs
提供了一種方式,容許咱們訪問DOM
節點或在render
方法中建立的React
元素。html
在典型的React
數據流中,props
是父組件與子組件交互的惟一方式,要修改一個子組件,你須要使用新的props
來從新渲染它,可是在某些狀況下,你須要在典型數據流以外強制修改子組件,被修改的子組件多是一個React
組件的實例,也多是一個DOM
元素,對於這兩種狀況React
都提供瞭解決辦法。
避免使用refs
來作任何能夠經過聲明式實現來完成的事情,一般在能夠使用props
與state
的狀況下勿依賴refs
,下面是幾個適合使用refs
的狀況:react
DOM
庫。React
提供的這個ref
屬性,表示爲對組件真正實例的引用,其實就是ReactDOM.render()
返回的組件實例,須要區分一下渲染組件與渲染原生DOM
元素,渲染組件時返回的是組件實例,而渲染DOM
元素時,返回是具體的DOM
節點,React
的ref
有3
種用法。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
回調會在componentDidMount
或componentDidUpdate
等生命週期回調以前執行。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} />; } }
在React v16.3
中經0017-new-create-ref
提案引入了新的React.createRef
的API
,當ref
被傳遞給render
中的元素時,對該節點的引用能夠在ref
的current
屬性中被訪問,ref
的值根據節點的類型而有所不一樣:數組
ref
屬性用於HTML
元素時,構造函數中使用React.createRef()
建立的ref
接收底層DOM
元素做爲其current
屬性。ref
屬性用於自定義class
組件時,ref
對象接收組件的掛載實例做爲其current
屬性。ref
屬性,由於他們沒有實例。對比新的CreateRef
與Callback Ref
,並無壓倒性的優點,只是但願成爲一個便捷的特性,在性能上會會有微小的優點,Callback Ref
採用了組件Render
過程當中在閉包函數中分配ref
的模式,而CreateRef
則採用了Object Ref
。babel
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