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

Redux Toolkit不可序列化值问题解决(不关闭校验方案)

解决Redux中存储File/Blob导致的序列化校验错误问题

问题背景

在Redux store的action payload中存储了File类型的下载文件,在saga中完成校验后,通过以下代码构建FormData发送至后端:

const form = new FormData();
 
if (privateKey && privateKey instanceof Blob) {
  const blob = new Blob([privateKey], { type: 'multipart/form-data' });
  form.append('privateKey', blob);   

每次下载文件后控制台触发序列化校验错误,需要在不关闭序列化校验的前提下解决该问题。

核心原因

Redux要求action payload和store中的state必须是可序列化的数据(如字符串、数字、数组、普通对象),而File/Blob属于浏览器原生的不可序列化对象,将其放入action payload时,会被Redux的serializableCheck中间件检测到并抛出错误。

可行解决方案

1. 避免在Redux中存储File/Blob实例,改用元数据+临时存储

  • 只在Redux中存储文件的可序列化元数据(如文件名、大小、MIME类型),实际的File/Blob对象存储在组件的useRef、全局变量或IndexedDB中。
  • 在saga处理时,直接从临时存储中获取文件对象,无需从Redux state/payload中读取。
  • 示例代码:
    // 组件中
    const fileRef = useRef(null);
    
    const handleFileSelect = (file) => {
      fileRef.current = file;
      // 只dispatch元数据到Redux
      dispatch(setFileMeta({
        name: file.name,
        size: file.size,
        type: file.type
      }));
    };
    
    // saga中
    function* uploadFileSaga() {
      const file = fileRef.current;
      if (file) {
        const form = new FormData();
        form.append('privateKey', file, file.name);
        // 发送请求
        yield call(api.upload, form);
      }
    }
    

2. 优化FormData构建逻辑,移除不必要的Blob转换

  • File本身是Blob的子类,无需重新创建Blob实例,直接将原File对象append到FormData即可,同时建议加上文件名参数,方便后端处理。
  • 修正后的代码:
    const form = new FormData();
    if (privateKey && privateKey instanceof Blob) {
      // 直接使用原对象,无需重新包装
      form.append('privateKey', privateKey, privateKey.name || 'private.key');
    }
    

3. 使用Redux Toolkit的异步工具处理非序列化数据

  • 若需要通过Redux流程传递文件,可使用Redux Toolkit的createAsyncThunk,它允许在payload中传递非序列化数据,但需注意不要将File/Blob存入store的state,仅在异步流程的payload中临时传递。
  • 示例代码:
    import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
    
    export const uploadFile = createAsyncThunk(
      'file/upload',
      async (file, { rejectWithValue }) => {
        try {
          const form = new FormData();
          form.append('privateKey', file, file.name);
          const response = await fetch('/api/upload', {
            method: 'POST',
            body: form
          });
          return await response.json();
        } catch (error) {
          return rejectWithValue(error.message);
        }
      }
    );
    
    // slice中只存储上传状态,不存储文件对象
    const fileSlice = createSlice({
      name: 'file',
      initialState: {
        loading: false,
        error: null,
        uploadResult: null
      },
      extraReducers: (builder) => {
        builder
          .addCase(uploadFile.pending, (state) => {
            state.loading = true;
            state.error = null;
          })
          .addCase(uploadFile.fulfilled, (state, action) => {
            state.loading = false;
            state.uploadResult = action.payload;
          })
          .addCase(uploadFile.rejected, (state, action) => {
            state.loading = false;
            state.error = action.payload;
          });
      }
    });
    
    export default fileSlice.reducer;
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:08:31