歡迎關注個人公衆號睿Talk
,獲取我最新的文章:
javascript
Race Condition 是開發中常常遇到的問題,好比查詢天氣的時候,先輸入「北京」,再輸入「深圳」,這時將發起 2 個請求。很可第一個請求花的時間比第二個請求長,若是不作處理,最終看到的是北京的天氣,而不是深圳。本文要討論的就是如何使用 React Hooks 解決這種問題。java
假設有以下搜索的場景,當用戶輸入關鍵字的時候,系統根據關鍵字搜索,而後實時顯示搜索結果。代碼以下:react
// 模擬網絡請求,能夠指定延遲時間 function getData(data, delay) { return new Promise(resolve => { setTimeout(()=>{ resolve(`${data} result`); }, delay); }) } function App() { const [query, setQuery] = useState('react'); const [result, setResult] = useState(); useEffect(() => { const fetchData = async () => { // 搜索 react1 時(第一個請求),2 秒後返回,其他 500 毫秒後返回 const delay = query === 'react1' ? 2000 : 500; const result = await getData(query, delay); setResult(result); } fetchData(); }, [query]); return ( <Fragment> <input type="text" value={query} onChange={event => setQuery(event.target.value)} /> <div> result: <span>{result}</span> </div> </Fragment> ); }
當咱們輸入react12345
時,能夠看到最終的結果是react1 result
,而咱們指望看到的結果是react12345 result
。segmentfault
這現象的緣由是更新數據的時候,沒有對結果的有效性進行判斷,用過時的數據覆蓋了最新的數據。網絡
解決方式很簡單,就是在更新數據前判斷其有效性,改造一下useEffect
部分的代碼:async
useEffect(() => { // 有效性標識 let didCancel = false; const fetchData = async () => { const delay = query === 'react1' ? 2000 : 500; const result = await getData(query, delay); // 更新數據前判斷有效性 if (!didCancel) { setResult(result); } } fetchData(); return () => { // query 變動時設置數據失效 didCancel = true; } }, [query]);
這裏利用了useEffect
數據清理的特性,當 query 發生變化時,將以前的數據請求設置爲失效。fetch
上面這種方案雖然解決了問題,但體驗並很差。在輸入數據的過程當中,並不能看到輸入過程當中返回的結果,只能看到最終的結果。咱們指望的效果是輸入過程當中能實時展現有效的結果。再改造下代碼:spa
// 請求序號 let seqenceId = 0; // 上一個有效請求的序號 let lastId = 0; function App() { const [query, setQuery] = useState('react'); const [result, setResult] = useState(); useEffect(() => { const fetchData = async () => { // 發起一個請求時,序號加 1 const curId = ++seqenceId; const delay = query === 'react1' ? 2000 : 500; const result = await getData(query,delay); // 只展現序號比上一個有效序號大的數據 if (curId > lastId) { setResult(result); lastId = curId; } else { console.log(`discard ${result}`); } } fetchData(); }, [query]); return ( ... ); }
這裏引入了 2 個變量,一個變量用來標識當前請求的序號,另外一個記錄上一個有效請求的序號。只有序號比上一個有效序號大的時候,才展現數據。這樣就保證了舊的請求不會覆蓋新的請求。code
最終的代碼能夠看這裏。ip
本文討論了開發過程當中常常遇到的 Race Condition 問題,結合 React Hooks 給出了 2 種解題思路。一種是隻展現最終的結果,隱藏過程結果;另外一種是將過程當中有效的結果也展現出來。能夠根據實際的應用場景按需選用。