TypeError: 循环结构转JSON错误:Socket.IO Client+RTK Query问题求助
解决RTK Query传入Socket实例时的循环结构序列化错误
错误原因
RTK Query在处理endpoint参数时,会对参数进行序列化(用于生成缓存键、日志记录等场景)。而Socket.IO客户端实例内部存在循环引用(比如socket实例与manager互相引用),直接将其作为参数传入endpoint会触发JSON序列化失败的错误。
解决方法
1. 将Socket实例全局注入到API切片(推荐)
不要在调用endpoint时传递Socket实例,而是在创建RTK Query的API切片时,通过extra参数注入Socket,在queryFn中直接使用:
// 创建API切片 const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/' }), endpoints: (builder) => ({ sendSocketMessage: builder.mutation({ queryFn: async (message, { extra }) => { // 从extra中获取预先注入的Socket实例 const socket = extra.socket; try { await socket.emit('send-message', message); return { data: '发送成功' }; } catch (err) { return { error: { status: 'CUSTOM_ERROR', error: err.message } }; } }, }), }), }); // 配置Store时注入Socket实例 const socket = io(); const store = configureStore({ reducer: { [api.reducerPath]: api.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ thunk: { extraArgument: { socket }, }, }).concat(api.middleware), }); // 调用endpoint时仅传递业务数据 dispatch(sendSocketMessage({ content: 'Hello Socket' }));
2. 封装Socket操作函数
提前封装好Socket的业务操作,在endpoint的queryFn中直接调用封装函数,避免直接传递Socket实例:
// 封装Socket工具函数 const socket = io(); export const socketService = { sendMessage: (message) => { return new Promise((resolve, reject) => { socket.emit('send-message', message, (response) => { response.success ? resolve(response) : reject(new Error(response.error)); }); }); }, }; // 在API切片中调用封装函数 const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/' }), endpoints: (builder) => ({ sendSocketMessage: builder.mutation({ queryFn: async (message) => { try { const data = await socketService.sendMessage(message); return { data }; } catch (err) { return { error: { status: 'CUSTOM_ERROR', error: err.message } }; } }, }), }), });
3. 自定义参数序列化逻辑(不推荐)
如果必须传递Socket实例,可通过serializeQueryArgs跳过对Socket的序列化,但可能影响缓存键的正确性,需谨慎使用:
const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/' }), // 自定义序列化逻辑,排除Socket实例 serializeQueryArgs: ({ queryArgs }) => { const { socket, ...validArgs } = queryArgs; return JSON.stringify(validArgs); }, endpoints: (builder) => ({ sendSocketMessage: builder.mutation({ queryFn: async ({ socket, message }) => { try { await socket.emit('send-message', message); return { data: '发送成功' }; } catch (err) { return { error: { status: 'CUSTOM_ERROR', error: err.message } }; } }, }), }), });
内容的提问来源于stack exchange,提问作者user19681931
相关产品推荐
相关产品推荐

