精讀《useRef 與 createRef 的區別》

1 引言

useRef 是經常使用的 API,但還有一個 createRef 的 API,你知道他們的區別嗎?經過 React.useRef and React.createRef: The Difference 這篇文章,你能夠了解到什麼時候該使用它們。html

2 概述

其實原文就闡述了這樣一個事實:useRef 僅能用在 FunctionComponent,createRef 僅能用在 ClassComponent。前端

第一句話是顯然的,由於 Hooks 不能用在 ClassComponent。react

第二句話的緣由是,createRef 並無 Hooks 的效果,其值會隨着 FunctionComponent 重複執行而不斷被初始化:git

function App() {
  // 錯誤用法,永遠也拿不到 ref
  const valueRef = React.createRef();
  return <div ref={valueRef} />;
}

上述 valueRef 會隨着 App 函數的 Render 而重複初始化,這也是 Hooks 的獨特之處,雖然用在普通函數中,但在 React 引擎中會獲得超出普通函數的表現,好比初始化僅執行一次,或者引用不變github

爲何 createRef 能夠在 ClassComponent 正常運行呢?這是由於 ClassComponent 分離了生命週期,使例如 componentDidMount 等初始化時機僅執行一次。微信

原文完。閉包

3 精讀

那麼知道如何正確建立 Ref 後,還知道如何正確更新 Ref 嗎?ide

因爲 Ref 是貫穿 FunctionComponent 全部渲染週期的實例,理論上在任何地方均可以作修改,好比:函數

function App() {
  const valueRef = React.useRef();

  valueRef.current += 1;

  return <div />;
}

但其實上面的修改方式是不規範的,React 官方文檔裏要求咱們避免在 Render 函數中直接修改 Ref,請先看下面的 FunctionComponent 生命週期圖:spa

從圖中能夠發現,在 Render phase 階段是不容許作 「side effects」 的,也就是寫反作用代碼,這是由於這個階段可能會被 React 引擎隨時取消或重作。

修改 Ref 屬於反作用操做,所以不適合在這個階段進行。咱們能夠看到,在 Commit phase 階段能夠作這件事,或者在回調函數中作(脫離了 React 生命週期)。

固然有一種狀況是能夠的,即 懶初始化

function Image(props) {
  const ref = useRef(null);

  // ✅ IntersectionObserver is created lazily once
  function getObserver() {
    if (ref.current === null) {
      ref.current = new IntersectionObserver(onIntersect);
    }
    return ref.current;
  }

  // When you need it, call getObserver()
  // ...
}

懶初始化的狀況下,反作用最多執行一次,並且僅用於初始化賦值,因此這種行爲是被容許的。

爲何對反作用限制的如此嚴格?由於 FunctionComponent 增長了內置調度系統,爲了優先響應用戶操做,可能會暫定某個 React 組件的渲染,具體能夠看第 99 篇精讀:精讀《Scheduling in React》

Ref 不只能夠拿到組件引用、建立一個 Mutable 反作用對象,還能夠配合 useEffect 存儲一個較老的值,最經常使用來拿到 previousProps,React 官方利用 Ref 封裝了一個簡單的 Hooks 拿到上一次的值:

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

因爲 useEffect 在 Render 完畢後才執行,所以 ref 的值在當前 Render 中永遠是上一次 Render 時候的,咱們能夠利用它拿到上一次 Props:

function App(props) {
  const preProps = usePrevious(props);
}

要實現這個功能,仍是要歸功於 ref 能夠將值 「在各個不一樣的 Render 閉包中傳遞的特性」。最後,不要濫用 Ref,Mutable 引用越多,對 React 來講可維護性通常會越差。

4 總結

你還挖掘了 useRef 哪些有意思的使用方式?歡迎在評論區留言。

討論地址是: 精讀《useRef 與 createRef 的區別》 · Issue #236 · dt-fe/weekly

若是你想參與討論,請 點擊這裏,每週都有新的主題,週末或週一發佈。前端精讀 - 幫你篩選靠譜的內容。

關注 前端精讀微信公衆號

版權聲明:自由轉載-非商用-非衍生-保持署名( 創意共享 3.0 許可證
相關文章
相關標籤/搜索