You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React路由参数变更及跨路由切换时组件状态未重置问题

问题分析与解决方案

1. loadedImages状态未正确重置的原因及修复

核心问题

  • 仅监听name参数重置状态,未关联categoryItems的更新:切换分类时,新的分类数据加载完成后才需要重置图片计数,否则旧分类的图片可能仍在加载并触发onLoad,导致计数混乱。
  • 组件卸载后仍可能触发状态更新:旧分类的CategoryItem卸载后,已加载的图片可能因缓存延迟触发onLoad,导致loadedImages被错误累加。

修复步骤

  • 关联分类数据更新重置计数:将重置loadedImages的useEffect依赖改为categoryItems,确保新分类数据加载完成后才重置计数:
useEffect(() => {
  setLoadedImages(0);
}, [categoryItems]);
  • 避免卸载组件的状态更新:在CategoryItem中添加挂载状态跟踪,确保仅组件挂载时更新计数:
const CategoryItem = ({ product, stylesFor="", setLoadedImages}) =>{
    const dispatch = useDispatch();
    const isMounted = useRef(true);

    useEffect(() => {
      return () => {
        isMounted.current = false;
      };
    }, []);

    const addItem = () =>{
        dispatch(cartActions.addItem(product))
    }

    const notifyImageLoad = () =>{
        if(isMounted.current && setLoadedImages){
            setLoadedImages(prev => prev +1)
        }
    }

    return(
        <div className={[classes["product-item"], classes[stylesFor]].join(' ')}>
            {/* 添加onError处理加载失败的情况 */}
            <img className={[classes["product-img"], classes[stylesFor]].join(' ')} 
                 src={product.img} 
                 onLoad={notifyImageLoad}
                 onError={notifyImageLoad} />
            <div className={[classes["product-desc-container"], classes[stylesFor]].join(' ')}>
                <h2 className={[classes["product-title"], classes[stylesFor]].join(' ')}>{product.title}</h2>
                <h2 className={[classes["product-desc"], classes[stylesFor]].join(' ')}>Something about product</h2>
                <h2 className={[classes["product-price"], classes[stylesFor]].join(' ')}>Price: {product.price}$</h2>
                <button onClick={addItem} className={[classes["add-button"], classes[stylesFor]].join(' ')}>ADD TO CART</button>
            </div>
        </div>
    )
}

2. 图片加载Spinner实现的合理性优化

当前实现逻辑方向正确,但存在两个潜在问题:

  • 图片加载失败时Spinner永不消失:未处理图片加载错误场景,导致loadedImages永远无法等于categoryItems.length。
  • 状态切换时序问题:仅监听name可能导致重置时机与数据更新不同步。

优化后的逻辑

保留loading(接口加载中)和loadedImages !== categoryItems.length(图片未加载完成)的判断,补充:

  • 给img标签添加onError事件,加载失败时同样计数,避免Spinner一直显示。
  • 确保loadedImages的重置与categoryItems强关联,保证时序正确。

最终调整后的CategoryPage关键代码

const CategoryPage = () =>{
    const { name } = useParams()
    const loading = useSelector(state => state.shop.loading)
    const categoryItems = useSelector(state => state.shop.categoryItems)
    const dispatch = useDispatch()
    const [loadedImages,setLoadedImages] = useState(0)

    useEffect(() => {
        dispatch(getShopData(`categories/${name}/products`,'category'))
    },[dispatch,name])

    // 当分类数据更新时重置图片加载计数
    useEffect(() =>{
        setLoadedImages(0)
    },[categoryItems])

    return(
        <>
            <img src={bg} className={classes["bg"]}/>
            {categoryItems.length > 0 && 
                <div className={classes["container"]}>
                    {categoryItems.map((product,id) =>
                        <CategoryItem key={id} product={product} setLoadedImages={setLoadedImages} /> 
                    )}
                </div>
            }
            {(loading || (categoryItems.length > 0 && loadedImages != categoryItems.length)) &&
                <div className="page-load-wrapper">
                    <Loader manualStyles={{width:"75px",height:"75px"}} />
                </div>
            }
        </>
    )
}

注:在Spinner的判断中添加categoryItems.length > 0,避免分类数据为空时不必要地显示Spinner。

内容的提问来源于stack exchange,提问作者James Hetfield

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 01:07:53