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

React调用API后setState更新延迟导致二次请求失败、组件崩溃如何解决?

问题根因

你代码里的问题主要出在这几个地方:

  • 渲染逻辑无兜底:secondData初始值是空字符串,直接访问secondData.blabla不存在的属性会直接导致组件崩溃
  • 第二接口URL错误:请求地址末尾多余拼接了HTTP/1.1字段,会直接导致接口请求失败
  • 位置权限错误未处理:navigator.geolocation.getCurrentPosition没有加错误回调,如果用户拒绝位置授权,整个逻辑会卡住,loading状态一直为true也不会抛出错误
  • 无副作用清理:如果组件在请求过程中卸载,未完成的请求回调执行setState会触发内存泄漏警告
  • third函数每次组件重渲染都会重新创建,存在冗余开销

修复方案

按以下调整即可解决所有问题:

  1. 渲染前先判断loading和secondData的状态,存在有效值再访问对应属性
  2. 删除第二个接口URL末尾多余的HTTP/1.1
  3. 补充位置授权的错误回调逻辑
  4. 用AbortController处理请求终止,避免内存泄漏
  5. 把third函数移到对应的useEffect内部,减少不必要的重复创建

完整修复后代码

const SecondDisplay = () => {
    const [firstData, setFirstData] = useState("")
    const [secondData, setSecondData] = useState("")
    const [errors, setErrors] = useState("")
    const [loading, setLoading] = useState(true)

    useEffect(() => {
        const controller = new AbortController()
        const signal = controller.signal

        const handleLocationError = (error) => {
            setErrors("位置权限获取失败,请授权后重试")
            setLoading(false)
        }

        navigator.geolocation.getCurrentPosition(function(position) {
            fetch(`https://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=AZvK08ugMNLlAGAwDD9GQGj108Tm8OIP&q=${position.coords.latitude}%2C${position.coords.longitude}&language=en-us&details=false&toplevel=false`, { signal })
            .then(res => {
                if(!res.ok){
                    throw Error("Sorry, something went wrong. please try again later.")
                }
                return res.json()
            })
            .then(data => {
                setFirstData({key: data.Key, name: data.AdministrativeArea.EnglishName})  
            })
            .catch(error => {
                if (error.name !== 'AbortError') {
                    setErrors(error.message)
                    setLoading(false)
                }
             })
            }, handleLocationError)
        
        // 清理函数,组件卸载时终止请求
        return () => controller.abort()
    }, [])

    useEffect(() => {
        if(firstData === "") return
        const controller = new AbortController()
        const signal = controller.signal

        fetch(`http://dataservice.accuweather.com/currentconditions/v1/${firstData.key}?apikey=AZvK08ugMNLlAGAwDD9GQGj108Tm8OIP&language=en-us&details=true`, { signal })
        .then(res => {
            if(!res.ok){
                throw Error("Sorry, something went wrong. please try again later.")
            }
            return res.json()
        })
        .then(data => {
            setSecondData(data)
            setLoading(false)
        })
        .catch(error => {
            if (error.name !== 'AbortError') {
                setErrors(error.message)
                setLoading(false)
            }
        })

        return () => controller.abort()
    }, [firstData])

    if (loading) return <p>加载中...</p>
    if (errors) return <p>{errors}</p>
    return(<p>{secondData?.blabla || "暂无数据"}</p>)
}

注:secondData?.blabla 是可选链语法,会在secondData为空的时候直接返回undefined,不会抛出异常,配合||做兜底展示即可。

内容的提问来源于stack exchange,提问作者BarakOren

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 08:18:01