React中useEffect内部使用filter方法不生效问题排查咨询
问题根因
该问题是三个React特性和代码逻辑错误共同导致的:
- useEffect闭包与依赖数组规则:你给useEffect传入了空依赖数组
[],这代表这个effect只会在组件首次挂载时执行1次,后续任何状态更新都不会触发它重新运行。 - state更新的异步性:
setAnotherObj是异步方法,调用后不会立刻修改当前作用域下的anotherObj值,本次effect闭包中捕获的anotherObj永远是组件挂载时的初始值(通常是空数组)。你同时发起了两个异步请求,两个请求的返回顺序不可控:如果getAPICall比getDBData先返回,过滤时用的anotherObj还是初始空值;就算getDBData先返回,因为effect不会重新执行,新的anotherObj也不会被用于过滤逻辑。 - 过滤逻辑本身错误:
Array.filter()返回的永远是数组,空数组在JS中属于真值,!anotherObj.filter(...)的判断逻辑永远返回false,相当于没有做任何有效过滤。这里应该用Array.some()来判断是否存在匹配项。
修复方案
可以用Promise.all等待两个异步请求都完成后再执行过滤,避免依赖顺序问题,也无需额外添加effect依赖:
useEffect(() => { Promise.all([getDBData(), getAPICall()]).then(([anotherObjRes, apiRes]) => { const result = apiRes.filter( o1 => !anotherObjRes.some(o2 => o1.name === o2.name) ); setAnotherObj(anotherObjRes); setOption(result); }) }, []);
如果业务场景需要两个请求分别独立触发、后续anotherObj更新时也要重新过滤,可以拆分effect:
const [apiData, setApiData] = useState([]); // 首次挂载拉取接口数据 useEffect(() => { getAPICall().then(r => setApiData(r)); }, []); // 首次挂载拉取DB数据 useEffect(() => { getDBData().then(r => setAnotherObj(r)); }, []); // api数据/DB数据更新时自动重新过滤 useEffect(() => { // 两个数据都存在时才执行过滤 if (!apiData.length || !anotherObj.length) return; const result = apiData.filter( o1 => !anotherObj.some(o2 => o1.name === o2.name) ); setOption(result); }, [apiData, anotherObj]); // 把依赖项加入数组,变动时自动重新执行
内容的提问来源于stack exchange,提问作者AnalyzingTasks
相关产品推荐
相关产品推荐

