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

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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 22:50:39