React JS中图片触发onerror时替换资源的解决方案(数组遍历场景)
React 图片加载失败自动替换备用地址解决方案
原有代码问题排查
- 全局共用单个
imgSrc状态:所有遍历渲染的图片共用同一个状态,任意一张图片加载失败会导致所有图片都替换为备用图 - 状态初始化逻辑错误:
password是map遍历的局部变量,父组件层级的useState无法访问该变量,初始值赋值无效 - 初始值语法错误:初始化
imgSrc时多余嵌套了反引号和双引号,生成的URL不符合预期 - 列表参数未做容错处理:从Redux获取的
passwordList未做空值兼容,可能出现解构报错
符合2021 React 开发规范的实现方案
推荐优先使用独立组件封装的方案,符合单一职责原则,复用性更强:
方案1:封装通用图片兜底组件
// 独立封装的带兜底的图片组件,可全局复用 const ImageWithFallback = ({ src, fallbackSrc, alt = "", ...rest }) => { const [imgSrc, setImgSrc] = useState(src); const handleError = () => { setImgSrc(fallbackSrc); }; return <img src={imgSrc} onError={handleError} alt={alt} {...rest} />; }; // 父组件使用 const PasswordList = () => { const dispatch = useDispatch(); const passwordList = useSelector((state) => state.passwordList); // return之前正确定义password相关参数,做空值容错 const { loading, error, passwords = [] } = passwordList || {}; const fallbackImg = "https://upload.wikimedia.org/wikipedia/commons/c/ce/Example_image.png"; if (loading) return <div>加载中...</div>; if (error) return <div>加载失败</div>; return ( <ul> {passwords.map((password) => ( <div key={password.id}> <li> <ImageWithFallback src={`https://example.com/${password.url}`} fallbackSrc={fallbackImg} alt={`密码项${password.id}`} /> </li> </div> ))} </ul> ); };
方案2:不拆组件的轻量实现
如果不需要复用组件,可通过记录加载失败的ID集合实现:
const PasswordList = () => { const dispatch = useDispatch(); const passwordList = useSelector((state) => state.passwordList); const { loading, error, passwords = [] } = passwordList || {}; const fallbackImg = "https://upload.wikimedia.org/wikipedia/commons/c/ce/Example_image.png"; // 存储加载失败的图片ID const [failedImgIds, setFailedImgIds] = useState(new Set()); const handleError = (id) => { setFailedImgIds(prev => new Set(prev).add(id)); }; if (loading) return <div>加载中...</div>; if (error) return <div>加载失败</div>; return ( <ul> {passwords.map((password) => ( <div key={password.id}> <li> <img src={failedImgIds.has(password.id) ? fallbackImg : `https://example.com/${password.url}`} onError={() => handleError(password.id)} alt={`密码项${password.id}`} /> </li> </div> ))} </ul> ); };
参数定义注意事项
在return前定义password相关参数时,需做如下兼容:
- 对从Redux获取的
passwordList做非空判断,避免undefined时解构报错 - 给
passwords设置默认空数组,避免map方法调用时报错
内容的提问来源于stack exchange,提问作者Toan Lam
相关产品推荐
相关产品推荐

