React 穿透獲取被高階元件裝飾的目標元件例項

不會撩妹的楚留香發表於2019-05-13

image

圖片來源於網際網路

React 中常規的父子元件通訊都是通過 props 進行的,子元件通過 props 來接收父元件傳遞的狀態值以及方法,從而響應檢視的更新以及事件的執行。

為什麼要獲取元件例項

在不同的業務場景中也會存在非常規的通訊方式,例如需要在父元件中呼叫子元件屬性或者方法,這個時候就需要獲取子元件的例項來解決這個問題。

獲取元件例項的方法

首先需要說明的是,只有類元件才有例項,函式式元件是沒有元件例項的。

React 官方提供了 3 中使用 ref 獲取例項的方式。

  1. ref 接收一個字串作為引數 (不推薦)
    class Index extends React.PureComponent {
    
        componentDidMount() {
            // 呼叫例項
            console.log(this.refs.classComponentInstance)
        }
        
        render() {
            return (
                <ClassComponent ref="classComponentInstance" />
            )
        }
    }
複製程式碼
  1. ref 接收一個回撥函式作為引數
    class Index extends React.PureComponent {
    
        componentDidMount() {
            // 呼叫例項
            console.log(this.classComponentInstance)
        }
        
        classComponentInstance = null
        
        render() {
            return (
                <ClassComponent ref={instance => {this.classComponentInstance=instance}} />
            )
        }
    }
複製程式碼
  1. ref 接收 React.createRef 作為引數
    class Index extends React.PureComponent {
    
        componentDidMount() {
            // 呼叫例項
            console.log(this.classComponentInstance.current)
        }
        
        classComponentInstance = React.createRef()
        
        render() {
            return (
                <ClassComponent ref={this.classComponentInstance} />
            )
        }
    }
複製程式碼

被高階元件裝飾的元件

所謂的高階元件也就一個函式,以元件作為引數,以元件作為返回值,主要是用於處理一些相似的邏輯,使元件可高度複用。


    // Child.js
    
    @HocComponent
    export default class Child extends React.PureComponent {
        
        render(
            return (
                <div>this is Child</div>
            )
        )
    }
    
    
    // Parent.js
    
    import Child from './Child'
    
    class Parent extends React.PureComponent {
    
        childComponentInstance = null
        
        render(
            return (
                <Child ref={instance => {this.childComponentInstance=instance}} />
            )
        )
    }
    
複製程式碼

關於裝飾符可檢視教程

上面示例中 Child 就是一個被高階元件使用裝飾符裝飾的類元件,當在 Parent 元件中呼叫並使用 ref 獲取其例項的時候就會發現 this.childComponentInstance 被賦值的例項並不是 Child 的例項,而是 HocComponent 元件的例項。

獲取被裝飾元件的例項


    // Child.js
    
    @HocComponent
    export default class Child extends React.PureComponent {
    
        componentDidMount() {
            // 在 componentDidMount 週期中或者在 constructor 建構函式中執行父元件中傳遞過來的 getRef 方法,將例項 this 作為引數
            this.props.getRef(this)
        }
        
        render(
            return (
                <div>this is Child</div>
            )
        )
    }
    
    
    // Parent.js
    
    import Child from './Child'
    
    class Parent extends React.PureComponent {
    
        childComponentInstance = null
        
        render(
            return (
                <Child getRef={instance => {this.childComponentInstance=instance}} />
            )
        )
    }

複製程式碼

通過上面的方式就可以穿透高階元件,獲取到目標元件的例項

抽象封裝為可複用的高階元件

上面的方法雖然已經實現了我們需要的功能,但是程式碼侵入性太強,沒有複用度可言,所以我們需要把這個功能提取出來。


    // util.js
    
    export const getRef = WrapperdComponent => {
        return props => {
            const { getRef, ...otherProps }  = props
            return <WrapperdComponent ref={getRef} {...otherProps} />
        }
    }
    
複製程式碼

當把穿透方法提取為一個高階元件之後就可以在任何需要的地方呼叫即可


    // 使用示例
    // Child.js
    
    import { getRef } from './util'
    
    @HocComponent
    @getRef
    export default class Child extends React.PureComponent {
        
        render(
            return (
                <div>this is Child</div>
            )
        )
    }
    
    
    
    // Parent.js
    
    import Child from './Child'
    
    class Parent extends React.PureComponent {
    
        childComponentInstance = null
        
        render(
            return (
                <Child getRef={instance => {this.childComponentInstance=instance}} />
            )
        )
    }
    
複製程式碼

最後

文中如有錯誤,歡迎在評論區指正,謝謝閱讀

相關文章