React应用中非循环gif仅首个播放动画,如何通过实例化解决?
问题原因
- 浏览器会对相同URL的静态资源做缓存,你所有GIF都使用了同一个src地址,第一个GIF加载完成播放到最后一帧后,后续新增的同src的img会直接复用缓存的已播放完毕的资源,因此直接显示最后一帧。
- 现有代码存在不符合React最佳实践的写法:将JSX元素存储在state中属于反模式,同时维护两个关联状态(
numbValue和starsValue)容易出现状态不同步问题,且列表渲染没有给元素加唯一key,React的Diff算法会错误复用之前的img DOM节点,也会导致GIF不重新播放。
解决方案
修改后的代码如下:
import { useState } from 'react'; function App(){ const [numbValue, numbUpdate] = useState(0); function Add(){ numbUpdate(prev => prev + 1); } function Sub(){ // 加最小值限制避免出现负数 numbUpdate(prev => Math.max(0, prev - 1)); } return(<> <p onClick={Add}>+</p> {Array.from({ length: numbValue }).map((_, index) => ( <img key={`star-${index}-${Date.now()}`} className="icon" src={`${process.env.PUBLIC_URL}/once-star-filled.gif?t=${Date.now()}-${index}`} alt="animated star" /> ))} <p onClick={Sub}>-</p> </>); }
修改说明
- 移除了冗余的
starsValue状态和DisplayGIF函数,直接根据numbValue的值渲染GIF列表,避免状态不同步问题 - 给每个GIF的src拼接了唯一的查询参数
t,值为当前时间戳+索引,强制浏览器每次新增GIF时都发起新的资源请求,不会复用缓存的已播放完毕的GIF资源 - 给每个img元素添加了唯一的key属性,保证React的Diff算法可以正确识别新增的元素,不会复用旧的DOM节点,确保GIF可以从头播放
内容的提问来源于stack exchange,提问作者user12246115
相关产品推荐
相关产品推荐

