在class組件中我們會用render返回一系列的組件或者DOM節點,有時我們需要獲取某一個DOM節點或者子組件的實例,然后去對他進行一些手動的操作,我們可以在componentDidMount生命周期函數內通過DOM選擇器來獲取對應的DOM對象,但是這不是很方便,因為很多需要都需要我們保存對應的DOM對象的引用,管理起來也有點麻煩。
我們可以用ref來獲取某個子節點的實例,然后通過當前class組件實例的一些特定屬性來直接獲取子節點實例。(vue里也有一個ref屬性,通過this.$refs來獲取DOM實例,兩個差不多的)
ref有三種實現方法:
- 字符串格式 ;字符串格式,這是React16版本之前用得最多的。 ;例如:<p ref="info">span</p>
- 函數格式 ;ref對應一個方法,該方法有一個參數,也就是對應的節點實例 ;例如:<p ref={ele => this.info = ele}></p>
- createRef方法 ;React16提供的一個API,使用React.createRef()來實現
方法一 字符串格式
我們可以在render函數內返回的jsx代碼片段中,給某個DOM節點或者子組件設置一個ref屬性,傳遞一個字符串,這樣當當前組件渲染完成后,我們可以通過當前class組件實例上的refs屬性獲取對應的一個DOM對象或者子組件實例
比如jsx中有這樣的一個代碼片段:<p ref="info">span</p>,之后我們就可以通過this.refs.info獲取到該p元素渲染后生成的DOM實例了。
舉個例子:
<div id="root"></div> <script type="text/babel"> class RefDemo extends React.Component{ state = {no:1} componentDidMount = ()=>{ this.refs.info.textContent = "no = "+this.state.no } //組件掛載完成后設置this.ref.info這個DOM節點的textContext test=()=>{ this.refs.info.textContent= "no = "+ ++this.state.no } //點擊測試按鈕后也修改this.ref.info這個DOM節點的textContext render(){ return ( <div> <button onClick={this.test}>測試</button> <p ref="info"></p> </div> ) } } ReactDOM.render(<RefDemo></RefDemo>,root) </script>
效果如下:
writer by:大沙漠 QQ:22969969
初始化時在componentDidMount生命周期函數內通過this.refs.info獲取到p元素的節點,之后設置它的textContext屬性,另外在測試按鈕上也綁定了一個test屬性,每次店家時遞增this.state.no,並設置在this.refs.info這個DOM節點上,也就是p節點對象了。
方法二 函數格式
上面例子里符串格式的ref在內部會轉換為一個函數格式,我們也可以直接將ref屬性的值設置為一個函數,該函數可以傳入一個參數,值是當前的DOM對象實例,比如:<p ref={ele => this.info = ele}></p>,這樣我們在當前class組件內可以直接通過this.info獲取到這個P元素的DOM對象實例了。
我們改寫一下上面的例子,用函數格式來寫一下,如下:
<div id="root"></div> <script type="text/babel"> class RefDemo extends React.Component{ state = {no:1} componentDidMount = ()=>{ this.info.textContent = "no = "+this.state.no } test=()=>{ this.info.textContent= "no = "+ ++this.state.no } render(){ return ( <div> <button onClick={this.test}>測試</button> <p ref={ele => this.info = ele}></p> //這里以函數的形式來寫,在其它邏輯內只需通過this.info就可以獲取這個p節點實例了 </div> ) } } ReactDOM.render(<RefDemo></RefDemo>,root) </script>
運行的效果和第一個例子是一樣了,就不截圖了。
方法三 createRef方法
createRef是React16新增的一個API,也是用於設置ref的,使用時,我們需要先執行
React.createRef()
執行后將返回一個{current: null}這樣的對象,我們在jsx內將React.createRef()的返回值作為值設置在一個DOM節點的ref屬性上,渲染后該DOM對象就會保存到React.createRef()返回的對象里的current屬性上了。
還是改寫一下第一個例子,我們用createRef方法來寫一下,如下:
<div id="root"></div> <script type="text/babel"> class RefDemo extends React.Component{ state = {no:1} domp = React.createRef(); //執行React.createRef()返回一個{current:null}對象 componentDidMount = ()=>{ this.domp.current.textContent = "no = "+this.state.no } test=()=>{ this.domp.current.textContent= "no = "+ ++this.state.no } render(){ return ( <div> <button onClick={this.test}>測試</button> <p ref={this.domp}></p> //設置ref屬性,值直接指向React.createRef()的返回值即可,也就是當前的domp屬性,之后在其它地方可以直接使用this.domp.current獲取這個P實例了 </div> ) } } ReactDOM.render(<RefDemo></RefDemo>,root) </script>
運行的效果和第一個例子也是一樣,這里也不貼截圖了,如果把ref設置在一個子節點組件上,則獲取的是組件實例。
除了普通DOM節點或自組件的節點外,如果我們在jsx代碼里引用了一個函數組件,由於在React當中函數組件也是返回jsx的,本身是沒有實例的,因此我們設置ref屬性獲取到的值是為空的,此時可以用React.forwardRef()來解決,React.forwardRef也是用到了createRef()方法,具體的我們下篇文章再講解。