React useEffect中cart过滤结果无法存入useState导致状态不一致如何解决
问题原因
- 执行时序错误:你当前的代码执行顺序是:组件挂载后触发useEffect,先执行
setArticle(cart.filter((e) => e.id === id)),此时cart还是初始值[],筛选结果必然是空;之后才调用异步的fetchCartAndPrice请求接口,等接口返回调用setCart更新购物车状态时,useEffect因为是空依赖不会再次执行,article也就不会再更新。 - 状态更新的快照特性:React的状态更新是异步的,就算你把setArticle放到fetchCartAndPrice内部的setCart后面,本次渲染周期里拿到的cart还是旧值,也没法立刻筛选出正确的结果。
- 方法使用不符合预期:
Array.filter返回的是符合条件的所有元素组成的数组,如果你只需要匹配id的单个商品,应该用Array.find,返回的是匹配到的单个元素,找不到则为undefined,更符合article的语义。
修复方案
拆分逻辑,把请求购物车和筛选article的逻辑分开,把需要响应变化的筛选逻辑放到单独的useEffect中,补充正确的依赖项:
const [article, setArticle] = useState(); const [cart, setCart] = useState([]); const { id } = useParams(); // 只负责请求购物车数据,挂载时执行一次 useEffect(() => { const fetchCartAndPrice = async () => { const { sess } = await ApiClientShoppingCart.getCart(); setCart(sess.cart); }; fetchCartAndPrice(); }, []); // cart或id变化时自动筛选对应的article useEffect(() => { setArticle(cart.find((e) => e.id === id)); }, [cart, id]); return ( <div> {console.log(cart.filter((e) => e.id === id))} {console.log(article)} </div> ); }
如果article没有其他需要手动更新的场景,也可以直接去掉对应的状态,在渲染层直接计算更简洁:
const [cart, setCart] = useState([]); const { id } = useParams(); // 直接计算,cart或id变化时会自动更新 const article = cart.find(e => e.id === id); useEffect(() => { const fetchCartAndPrice = async () => { const { sess } = await ApiClientShoppingCart.getCart(); setCart(sess.cart); }; fetchCartAndPrice(); }, []); return ( <div> {console.log(cart.filter((e) => e.id === id))} {console.log(article)} </div> ); }
内容的提问来源于stack exchange,提问作者C.G.
相关产品推荐
相关产品推荐

