React return中shopFiltered.map is not function及相关异常问题求助
问题根因拆解
- 核心语法错误:误将数组push方法的返回值作为组件状态
Array.prototype.push()的返回值是数组完成push操作后的新长度,并非修改后的数组本身。当前代码中setShopFiltered(shopFiltered.push(shop))的写法,本质是把每次push得到的长度数字直接设置为state:
由于第一个useEffect依赖项为空数组,闭包内捕获的shopFiltered永远是组件首次渲染时的初始空数组引用。每次Geocode异步回调触发时,都会往这个固定的空数组里追加元素,同时把当前数组长度作为新的state值,完全匹配控制台三次打印的表现:- 组件首次挂载时,依赖
[shopFiltered]的useEffect执行,打印初始空数组(即观察到的对象数组形式) - 第一个满足距离条件的shop触发push操作,返回长度1并设置为state,触发useEffect打印整型1
- 第二个满足距离条件的shop触发push操作,返回长度2并设置为state,触发useEffect打印整型2
当state被更新为数字类型后,渲染逻辑中调用shopFiltered.map()时,会直接抛出shopFiltered.map is not a function错误——数字类型本身不存在map方法。
- 组件首次挂载时,依赖
- 异步流程无清理逻辑触发内存泄漏警告
第一个useEffect中触发了axios请求、循环发起的多个Geocode异步请求,这些异步流程没有配套的取消/状态标记逻辑。如果组件在所有异步请求返回前被卸载,后续异步回调触发时仍会尝试调用setState,就会触发“Can't perform a React state update on an unmounted component”的提示。
修正方案
- 修正状态更新逻辑,避免类型错误
摒弃直接操作闭包原数组、传入push返回值的写法,改用函数式状态更新生成全新数组引用:
将原代码中
修改为if (dis / 1000 > 10) { setShopFiltered(shopFiltered.push(shop)); }if (dis / 1000 > 10) { setShopFiltered((prevShops) => [...prevShops, shop]); } - 增加异步清理逻辑,消除无效状态更新
在对应useEffect中增加挂载状态标记,在清理函数中标记组件卸载状态,所有异步回调触发setState前先校验挂载状态:
注:渲染逻辑中useEffect(() => { let isMounted = true; axios .get("My url which returns the data") .then((resp) => { resp.data.forEach((shop) => { Geocode.fromAddress(shop.acf.address).then( (response) => { let dis = getDistance( { latitude: parseFloat( response.results[0].geometry.location.lat ), longitude: parseFloat( response.results[0].geometry.location.lng ), }, { latitude: parseFloat(userCoords.lat), longitude: parseFloat(userCoords.lng), } ); if (isMounted && dis / 1000 > 10) { setShopFiltered((prevShops) => [...prevShops, shop]); } }, (error) => { console.error(error); } ); }); }); return () => { isMounted = false; }; }, []);!!shopFiltered && shopFiltered.map()的冗余判断可删除,修正后shopFiltered的类型会始终保持为数组。
内容的提问来源于stack exchange,提问作者brunelli
相关产品推荐
相关产品推荐

