因爲剛使用 React hooks 不久,對它的脾氣還拿捏不許,掉了不少次「坑」;這裏的 「坑」 的意思並非說 React hooks 的設計有問題,而是我在使用的時候,由於尚未跟上它的理念致使的一些問題。html
在讀了一些文章後,大體是找到本身老是掉坑的緣由了 —— 沒理解 React Hooks 中的 Capture Value 特性。react
本文就以簡單的示例來解釋這個特性所產生的現象,對理解 Capture Value 特性作一個補充。git
「這個 effects 取的值怎麼不是最新的?!」這個疑惑能夠說是在使用 React Hooks 時常常遇到的疑問。github
在下列代碼中,當你點擊按鈕 3s 後,alert 顯示的數值倒是 3s 前的 count 變量 —— 即沒法獲取最新的值,獲取的值是過去某個時刻的:web
import React, { useState, useCallback } from "react"; import ReactDOM from "react-dom"; function Example() { const [count, setCount] = useState(0); const handleAlertClick = useCallback(()=>{ setTimeout(() => { alert('You clicked on: ' + count); }, 3000) }, [count]); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> 增長 count </button> <button onClick={handleAlertClick}> 顯示 count </button> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render(<Example />, rootElement);
示例代碼: https://codesandbox.io/s/k5pm...
具體操做步驟:編程
這是官方特地設置的機制,官方原文是:This prevents bugs caused by the code assuming props and state don’t change;(強行翻譯一下,大概意思是:防止因 React 認爲 props
或者 state
沒有變動而引發的 bug)segmentfault
爲了理解官方這麼設定的意圖,將上面代碼稍微修改一下:微信
顯示 count
按鈕減小 count
的按鈕useEffect
代替 useCallback
,讓每次更改 count 都會彈窗... useEffect(()=>{ setTimeout(() => { alert('count: ' + count); }, 3000) }, [count]); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> 增長 count </button> <button onClick={() => setCount(count - 1)}> 減小 count </button> </div> ); } ...
咱們先點擊一次 增長 count
,而後再緊接着點擊一次 減小 count
:dom
count
數值都是 0 —— 很明顯這不是咱們想要的總結起來,這個現象其實就是文章 精讀《useEffect 徹底指南》 所說起的 Capture Value 特性(能夠自行前往原文了解更多細節)ide
count
變量回到原來的問題,倔強如我,我就是想要在 3s 後獲取的是此時此刻的 count
變量,而不是我 3s 前點擊時的 count
值,該怎麼操做?
官方給出的解決方案是,每次改變 count
的時候,將其放在 ref 類型的變量裏便可。
修改一下原來的代碼:
const countRef = useRef(null); const handleAlertClick = useCallback( () => { setTimeout(() => { alert("You clicked on: " + countRef.current); }, 3000); }, [count] ); return ( <div> <p>You clicked {count} times</p> <button onClick={() => { countRef.current = count + 1; setCount(count + 1); }} > 增長 count </button> <button onClick={handleAlertClick}>顯示 count</button> </div> );
更改事後的代碼運行後,3s
後 alert 顯示的 count
變量就是你頁面上所見到的樣子了:
ref 類型的變量一般是用來存儲 DOM 元素引用,但在 react hooks 中,它能夠存聽任何可變數據,就比如類實例屬性同樣,具體參考 Is there something like instance variables?
這等操做,其實就是藉助 ref
類型變量繞過 Capture Value 特性來達到目的。
援引文章 精讀《useEffect 徹底指南》 中對 Capture Value 概念的解釋:每次 Render 的內容都會造成一個快照並保留下來,所以當狀態變動而 Rerender 時,就造成了 N 個 Render 狀態,而每一個 Render 狀態都擁有本身固定不變的 Props 與 State。
經過這個示例,相信會比較容易地理解 Capture Value 特性,並如何使用 ref
來暫時繞過它。在知道並理解這個特性後,有助於進一步熟悉了 React Hooks 的運行機制,減小掉坑的次數。
這裏羅列幾篇文章,方便自檢是否掌握了這個概念:
setInterval
和 Hooks
和諧地玩耍,爲何是這種方式,以及這種方式給你帶來了什麼新能力。useRef
來解決,也有人針對它進行了封裝(How to compare oldValues and newValues on React Hooks useEffect?)下面的是個人公衆號二維碼圖片,歡迎關注。