useRef
是經常使用的 API,但還有一個 createRef
的 API,你知道他們的區別嗎?經過 React.useRef and React.createRef: The Difference 這篇文章,你能夠了解到什麼時候該使用它們。html
其實原文就闡述了這樣一個事實: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
等初始化時機僅執行一次。微信
原文完。閉包
那麼知道如何正確建立 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 來講可維護性通常會越差。
你還挖掘了 useRef
哪些有意思的使用方式?歡迎在評論區留言。
討論地址是: 精讀《useRef 與 createRef 的區別》 · Issue #236 · dt-fe/weekly
若是你想參與討論,請 點擊這裏,每週都有新的主題,週末或週一發佈。前端精讀 - 幫你篩選靠譜的內容。
關注 前端精讀微信公衆號
版權聲明:自由轉載-非商用-非衍生-保持署名( 創意共享 3.0 許可證)