欢迎关注个人公众号睿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 种解题思路。一种是只展现最终的结果,隐藏过程结果;另外一种是将过程当中有效的结果也展现出来。能够根据实际的应用场景按需选用。