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 許可證)