useEffect调用图片预加载函数过快失效,重渲染后正常如何解决
问题根源
- 图片的
onload回调是异步执行的,你同步调用handleLoading时,所有图片的加载请求才刚发出,onload回调还没有触发,counter自然还是0,所以判断条件永远无法满足,loading状态不会更新为false。 - 用来计数的
counter是loadImages函数内部的局部变量,每次onload触发修改counter后,没有主动触发加载完成的判断逻辑,也不会触发组件更新,所以只有组件因为其他原因重渲染时,你才能看到counter的数值变化。
修复方案
你可以把加载完成的判断逻辑放到onload回调中,每次单张图片加载完成后都检查是否所有图片加载完毕,修改后的代码如下:
const { products } = useContext(WPContext); const [productsList, setProductsList] = useState(products); const [filteredList, setFilteredList] = useState(products); const [loading, setLoading] = useState(false); useEffect(() => { loadImages(products); }, [products]); // 增加products作为依赖,避免上下文数据更新后逻辑不触发 const loadImages = (allProducts) => { let counter = 0; setLoading(true); const totalCount = allProducts.length; const newProducts = allProducts.map((product) => { const newImg = new Image(); newImg.src = "https://via.placeholder.com/450x630"; const handleLoadFinish = () => { counter += 1; if (counter >= totalCount) { setLoading(false); setFilteredList(newProducts); } } // 加载成功触发判断 newImg.onload = handleLoadFinish; // 加载失败也触发判断,避免loading永久为true newImg.onerror = handleLoadFinish; return { ...product, acf: { ...product.acf, product_image: { ...product.acf.product_image, url: newImg.src, }, }, }; }); };
额外注意事项
- 如果后续商品数量会动态变化,建议用
useRef存储counter变量,避免出现闭包陷阱 - 如果需要对加载失败的图片做降级处理,可以在
onerror回调中补充替换默认图的逻辑
内容的提问来源于stack exchange,提问作者Donnie Berry
相关产品推荐
相关产品推荐

