React页面重载后无法动态渲染依赖状态的图片求助
问题:React动态加载图片在页面重载后无法显示
我有一个React组件,尝试动态加载图片,该图片依赖通过useEffect从后端获取的状态,初始状态为空。当我通过表单内的下拉列表修改状态时,图片能正常显示,但页面重载后图片无法显示。我尝试用loading作为标识,在fetch请求完成后修改其值以延迟组件(或仅img标签)的渲染,但页面重载时winner的值仍为undefined,图片无法加载。代码如下:
const Winner = () => { const [winner, setWinner] = useState({"id": "", "name": ""}) const [loading, setLoading] = useState(true) useEffect(() => { fetch(`/api/v1/winner`, { method: 'GET', credentials: 'include', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, }) .then(res => res.json()) .then(jsonData => { setWinner(jsonData) setLoading(false) }) .catch((error) => { console.log(error) }) }, []) return ( (loading ? <p>Loading..</p> : <Box className="bonus"> <img src={`./static/${winner.name}.png`.toLowerCase()} width="40px" height="40px" /> <FormControl> ... </FormControl> </Box> )) }
解决方案
1. 校验后端返回数据的有效性
页面重载后图片失效,核心原因大概率是后端返回的jsonData结构不符合预期:比如name字段为空、不存在,或者返回了undefined。即使设置了初始状态,若后端数据异常,winner.name仍会生成无效的图片路径。
解决方式:在设置状态前强制校验数据,为缺失字段设置默认值:
.then(jsonData => { const validData = { id: jsonData?.id || "", name: jsonData?.name || "" } setWinner(validData) setLoading(false) })
2. 修正静态资源路径
React项目(尤其是Create React App)中,public文件夹下的静态资源需要使用绝对路径(以/开头),而非相对路径./。页面重载时,相对路径会随当前路由变化,导致资源寻址失败。
修改图片路径:
// 原相对路径 // `./static/${winner.name}.png`.toLowerCase() // 改为绝对路径 `/static/${winner.name.toLowerCase()}.png`
3. 增加图片渲染的条件判断
即使loading状态结束,也要确保winner.name有效后再渲染图片,避免生成无效的src属性:
// 替换原img标签 {winner.name && ( <img src={`/static/${winner.name.toLowerCase()}.png`} width="40px" height="40px" alt={winner.name} // 增加alt属性提升可访问性 /> )}
4. 完善错误处理逻辑
当前代码仅在catch块打印错误,但未更新loading状态,若请求失败,页面会一直显示加载中。同时要处理HTTP请求的状态错误(比如404、500):
useEffect(() => { fetch(`/api/v1/winner`, { method: 'GET', credentials: 'include', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, }) .then(res => { // 校验HTTP响应状态 if (!res.ok) throw new Error(`请求失败:${res.status}`) return res.json() }) .then(jsonData => { const validData = { id: jsonData?.id || "", name: jsonData?.name || "" } setWinner(validData) setLoading(false) }) .catch((error) => { console.error('获取获奖者数据失败:', error) setLoading(false) // 即使请求失败也停止加载状态 }) }, [])
完整修改后的代码
const Winner = () => { const [winner, setWinner] = useState({"id": "", "name": ""}) const [loading, setLoading] = useState(true) useEffect(() => { fetch(`/api/v1/winner`, { method: 'GET', credentials: 'include', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, }) .then(res => { if (!res.ok) throw new Error(`请求失败:${res.status}`) return res.json() }) .then(jsonData => { const validData = { id: jsonData?.id || "", name: jsonData?.name || "" } setWinner(validData) setLoading(false) }) .catch((error) => { console.error('获取获奖者数据失败:', error) setLoading(false) }) }, []) return ( loading ? <p>Loading..</p> : <Box className="bonus"> {winner.name && ( <img src={`/static/${winner.name.toLowerCase()}.png`} width="40px" height="40px" alt={winner.name} /> )} <FormControl> ... </FormControl> </Box> ) }
内容的提问来源于stack exchange,提问作者Chen A.
相关产品推荐
相关产品推荐

