You need to enable JavaScript to run this app. Redux Toolkit 向payload传Error报不可序列化错误(不禁用serializableCheck)解决
优惠活动
大模型
产品
解决方案
定价
更多

Redux Toolkit 向payload传Error报不可序列化错误(不禁用serializableCheck)解决

合规传递Error类错误信息的落地方案(无需修改RTK序列化校验配置)

所有方案均满足Redux Toolkit默认的可序列化校验规则,不会触发Non-serializable value was detected in action报错:

  • 提取Error核心字段构造纯普通对象,作为action payload传入
    直接传入Error实例被拦截的核心原因是,Error是带原型链的非普通对象,不属于RTK序列化校验允许的原始值、Plain Object、数组类型。你可以在dispatch前,手动提取Error实例上的可序列化字段,构造纯对象再传入:

    // 会触发校验报错的写法
    dispatch(handleRequestError(new Error('接口超时')))
    
    // 合规写法
    const rawError = new Error('接口超时')
    dispatch(handleRequestError({
      name: rawError.name,
      message: rawError.message,
      stack: rawError.stack,
      // 可按需挂载自定义错误码、错误元信息
      code: rawError.code
    }))
    

    存入store的字段全部是字符串、数字这类可序列化值,可直接通过useSelector取出传递给组件;如果需要恢复完整Error实例能力,在组件拿到plain错误对象后,通过const restoredError = new Error(errObj.message)重新构造实例,再把其他自定义字段挂在实例上即可。

  • 依托createAsyncThunk的内置错误处理机制,自动生成合规的可序列化错误payload
    RTK的createAsyncThunk本身就做了错误信息的序列化适配,不需要手动处理Error实例透传的问题:在异步流程捕获到错误时,通过rejectWithValue返回纯普通对象格式的错误信息,这个返回值会直接作为rejected action的payload,全程不会触发序列化校验:

    const fetchOrderDetail = createAsyncThunk(
      'order/fetchDetail',
      async (orderId, { rejectWithValue }) => {
        try {
          const res = await fetch(`/api/order/${orderId}`)
          if (!res.ok) throw new Error(`请求失败,状态码${res.status}`)
          return res.json()
        } catch (err) {
          // 返回的纯对象会作为action payload,完全通过序列化校验
          return rejectWithValue({
            message: err.message,
            statusCode: res.status
          })
        }
      }
    )
    

    在slice的reducer中匹配rejected状态,把拿到的错误信息存入state,组件即可直接从state读取错误信息,不需要手动构造带Error的action。

  • 旁路映射表存储原始Error实例,store中仅传递可序列化的唯一标识
    如果业务流程中确实需要在组件中使用原始Error实例的全量能力(比如依赖instanceof判断错误类型、调用Error实例的内置方法),可以不用把Error本身放进store:

    1. 在模块作用域下维护一个Map结构,作为Error实例的存储映射,这个Map不属于store的一部分,不会触发任何序列化检查
    2. 给每个捕获到的Error分配一个唯一字符串ID,把<ID, Error实例>的键值对存在这个Map里
    3. dispatch action时,只把这个唯一ID作为payload传入store
    // 模块级旁路存储,不进Redux store
    const errorStore = new Map<string, Error>()
    let incrementId = 0
    
    const registerError = (err: Error) => {
      const errId = `err_${incrementId++}`
      errorStore.set(errId, err)
      return errId
    }
    
    // 组件中捕获错误后的调用逻辑
    const caughtErr = new Error('自定义业务错误')
    const errId = registerError(caughtErr)
    dispatch(setActiveError({ errId }))
    
    // 组件读取错误时的逻辑
    const activeErrId = useSelector(state => state.app.activeErrId)
    const activeError = errorStore.get(activeErrId)
    

    整个流程中进入action、存入store的只有字符串类型的errId,完全符合序列化校验要求,同时能在组件中拿到原始Error实例的全部能力。注意:读取完对应的Error实例后,可通过errorStore.delete(errId)清理映射表中的引用,避免不必要的内存占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 14:45:03