React 源碼解析 - API 系列 - React.createRef/forwardRef

前言

這篇一樣繼續來分析 react 中的 createRef() 以及 forwardRef() 這兩個 api,首先也會先說說 ref 的概念以及在 react 中的使用方式,然後再來分析 react 中關於這兩個方法的源碼實現。

正文

首先先來看看 ref 在 react 中的基本用法以及一些概念,當然如果熟悉的人就跳過直接看源碼吧!

關於 ref

其實 ref 也就是 reference 的縮寫,就是個引用。我們可以來看看 react 中關於 ref 有哪些重要的概念以及用法吧~

ref 的由來

在典型的 react 數據流中,或者說是 react 標榜推崇的數據流模式中,props 是父組件與子組件交互的唯一方式。要修改一個子組件,你需要使用新的 props 來重新渲染它,但是,在某些情況下,你需要在典型數據流之外強制修改子組件/元素。

我們來看看 react ref 具體有哪些用法:

在 react 16.3 以前比較常使用的,通常 ref 可以通過綁定字符串(string ref)或是回調函數(callback ref)獲取。

string ref

// string ref

class App extends React.Component {
   
    componentDidMount() {
   
        this.refs.myRef.focus()
    }

    render() {
   
        return <input ref="myRef" />
    }
}

這是最原始的 ref 使用方式,可是這種方式即將被淘汰,而且官方也說得很清楚:

如果你目前還在使用 this.refs.textInput 這種方式訪問 refs ,我們建議用回調函數或 createRef API 的方式代替。

具體壞處參考這篇 一文搞懂 React ref,寫得還算清楚。

callback ref

// callback ref

class App extends React.Component {
   
    componentDidMount() {
   
        this.myRef.focus()
    }

    render() {
   
        return <input ref={
   ele => this.myRef = ele} />
    }
}

這邊說下對 callback ref 的理解,因為會與 createRef 牽涉到一些比較,搞懂下還是好點。

其實 react 在掛載組件之前,會調用 ref 的回調函數並傳入目標 dom 元素,當卸載組件時同樣會再次調用,不過這時候參數變為 null。在 ComponentDidMount 以及 ComponentDidUpdate 之前,react 會保證所有 ref 都是最新的。

callback ref 的使用方式也會影響到 react 的性能。如果我們以內聯函數的形式直接定義在 dom 元素上,那在組件更新的過程中這個回調函數會被執行兩次。因為 react 更新組件相當於先卸載再掛載,所以每次更新 react 都要先傳入 null 清空舊組件(第一次),然後再傳入 dom 元素進行新的函數實例的掛載(第二次)。

我們通過將 ref 回調函數綁定在 class 上的方式可以避免這種問題,不過其實大部分情況下無所謂的。整體來說,callback ref 是比較推薦的,且性能上也比較好的方式。

createRef

在 react 16.3 之後,新的提案引入了一個新的 api,也就是本文的主角 - createRef。來看看具體怎麼用:

// createRef

class App extends React.Component {
   
    constructor(props) {
   
        super(props)
        this.myRef = React.createRef()
    }
    
    componentDidMount() {
   
        this.myRef.current.focus()
    }

    render() {
   
        <input ref={
   this.myRef} />
    }
}

createRef 優點是相對於 callback ref 更加直觀些,也避免了一些對於回調函數理解上的問題。createRef 缺點則是性能略低於 callback ref。

通過 createRef 創建的 ref 的值會根據節點類型而有所不同:

當 ref 屬性用於 HTML 元素時,構造函數中使用 React.createRef() 創建的 ref 接收底層 DOM 元素作為其 current 屬性。

  • 當 ref 屬性用於自定義 class 組件時,ref 對象接收組件的掛載實例作為其 current 屬性。

  • 默認情況下,你不能在函數組件上使用 ref 屬性(可以在函數組件內部使用),因為它們沒有

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值