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

React useEffect搭配React-Query useQuery全局错误处理错误重复添加问题

问题根因
  • AlertProvider每次渲染都会重新生成context的value对象,导致useAlertContext()返回的引用持续变化,触发useAccess中useEffect的重复执行。
  • React Query请求失败后,query.isError和query.error会长期保持错误状态,不会因为全局alert被清空就自动重置,只要useEffect触发就会满足判断条件,重新添加错误。
修复方案

1. 稳定AlertContext的value引用(基础修复)

用useMemo包裹context的value,只有依赖项变化时才生成新对象,避免不必要的引用更新:

import React, { useState, createContext, useContext, useMemo } from 'react'

const AlertContext = createContext()

const AlertProvider = ({ children }) => {
  const [alert, setAlert] = useState(null)

  const removeAlert = () => setAlert(null)
  const addAlert = (message) => setAlert(message)

  // 稳定context引用
  const contextValue = useMemo(() => ({
    alert,
    add: addAlert,
    remove: removeAlert
  }), [alert])

  return (
    <AlertContext.Provider value={contextValue}>
      {children}
    </AlertContext.Provider>
  )
}

const useAlertContext = () => {
  return useContext(AlertContext)
}

export {
  AlertProvider as default,
  useAlertContext
}

2. 优化错误添加逻辑,避免重复添加

在useAccess的useEffect中增加重复判断,相同错误不会重复插入:

useEffect(() => {
  const errorMsg = query.error?.toString()
  if (query.isError && alertContext.alert !== errorMsg) {
    alertContext.add(errorMsg)
  }
}, [alertContext, query.isError, query.error])

3. 最优方案:使用React Query原生onError回调

直接用useQuery内置的错误回调,请求失败时只会触发一次,完全规避useEffect依赖导致的重复执行问题,不需要额外写useEffect:

export const useAccess = () => {
  const alertContext = useAlertContext()
  const route = '/accessx'
  const query = useQuery(route, async () => await ApiV4.get(route), {
    retry: 0,
    // 错误回调仅在请求失败时触发一次
    onError: (err) => alertContext.add(err.toString())
  })

  return query
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 21:24:00