Next.js项目Redux Reducer更新初始状态返回Undefined问题求助
问题描述
在使用Redux的Next.js项目中,向服务器提交新任务后,尝试更新Reducer状态以实时展示新任务,但更新时返回undefined。
相关代码
TaskSlice 代码
import { createSlice } from "@reduxjs/toolkit"; import Cookies from "universal-cookie"; import { decode } from "jsonwebtoken"; const cookie = new Cookies(); const token = cookie.get("token"); export const initialState: any = { tasks: [], status: "idle", }; // ========== Thunks ========== import { taskThunk } from "./thunks/task.thunk"; import { useGraphql } from "../../../helper/useGraphql"; const TaskSlice = createSlice({ name: "task", initialState, reducers: { createTask: async (state, actions) => { const { id }: any = decode(token); try { const { taskName, taskTags } = actions.payload; const graphqlSchema = ` mutation addTask($taskInput: TaskInput!) { createTask(taskInput: $taskInput) { _id taskName tags { color name } } } `; const variables = { taskInput: { taskName: taskName, tags: taskTags, userId: id, }, }; const { response } = await useGraphql(graphqlSchema, variables); const newElement = response.data.createTask; state.tasks = state.tasks.; return state; } catch (error) { console.log("Error in createTask reducer:", error); throw error; } }, }, extraReducers: (builder) => { builder.addCase(taskThunk.fulfilled, (state, actions) => { try { const tasks = actions.payload.getTasks; state.tasks = tasks; state.status = "success"; } catch (error) { throw error; } }); }, }); export const { createTask } = TaskSlice.actions; export default TaskSlice.reducer;
useGraphql 工具函数
import axios from "axios"; export const useGraphql = async (schema: string, variables?: any) => { const graphqlSchema = { query: schema, variables: variables, }; try { const sendRequest = await axios({ url: "http://localhost:5000/", method: "POST", data: JSON.stringify(graphqlSchema), headers: { "Content-Type": "application/json", }, }); const response = sendRequest.data; return { response: response, }; } catch (error) { throw error; } };
TaskCreatorForm 组件
import { useState } from "react"; // =========== Components ========== import Input from "../../../UIElements/input"; import Tags from "../../../UIElements/tags"; import Wrapper from "../wrapper.form"; // =========== Redux ========== import { AppDispatch } from "../../../../redux/store"; import { useDispatch } from "react-redux"; import { createTask } from "../../../../redux/slices/tasks/index.slice"; const TaskCreatorForm = () => { const [taskName, setTaskName] = useState<String>(""); const [taskTags, setTaskTags] = useState<Array<Object>>([]); const dispatch = useDispatch<AppDispatch>(); const createTaskHandle = () => { const payload: any = { taskName, taskTags, }; dispatch(createTask(payload)); }; return ( <Wrapper admitFunction={createTaskHandle}> <Input placeholder="Task Name" type="text" label="Task Name" giveValue={setTaskName} requireSign={true} /> <Tags giveValue={setTaskTags} coloration={true} placeholder="add tags" label="add Task" /> </Wrapper> ); }; export default TaskCreatorForm;
Wrapper 组件
import { useContext } from "react"; // =========== Components =========== import { PrimaryButton } from "../../UIElements"; // =========== context =========== import { modalContext } from "../../../context/modal.context"; const Wrapper = ({ children, admitFunction }: any) => { const { toggleModal } = useContext(modalContext); return ( <div className="flex flex-col gap-6"> {children} <div className="flex items-center justify-end w-full gap-4"> <PrimaryButton color="transparent" className="!text-black" onClick={() => toggleModal("taskcreator")} > Close </PrimaryButton> <PrimaryButton onClick={admitFunction} className="shadow-sm"> admit </PrimaryButton> </div> </div> ); }; export default Wrapper;
问题分析与修复
1. Reducer 不能包含异步逻辑
Redux Toolkit 的 reducers 字段中的函数必须是同步的,你在 createTask reducer 中使用了 async/await,这会导致状态更新失效——异步函数返回的是 Promise,而 Reducer 需要直接修改状态(或返回新状态)。
修复: 将异步请求逻辑移到 Redux Thunk 中,不要在 reducer 里处理异步操作。
2. 状态更新代码存在语法错误
state.tasks = state.tasks.; 这行代码有语法错误,缺少了数组操作逻辑。正确的做法是将新任务添加到现有数组中:
// 方式1:使用 Immer 直接修改(Redux Toolkit 内置支持) state.tasks.push(newElement); // 方式2:返回新数组 state.tasks = [...state.tasks, newElement];
3. 正确实现方案
步骤1:创建 CreateTask Thunk
在 task.thunk.ts 中添加异步逻辑:
import { createAsyncThunk } from "@reduxjs/toolkit"; import Cookies from "universal-cookie"; import { decode } from "jsonwebtoken"; import { useGraphql } from "../../../helper/useGraphql"; const cookie = new Cookies(); const token = cookie.get("token"); export const createTaskThunk = createAsyncThunk( "task/createTask", async (payload: { taskName: string; taskTags: Array<Object> }) => { const { id }: any = decode(token); const { taskName, taskTags } = payload; const graphqlSchema = ` mutation addTask($taskInput: TaskInput!) { createTask(taskInput: $taskInput) { _id taskName tags { color name } } } `; const variables = { taskInput: { taskName, tags: taskTags, userId: id, }, }; const { response } = await useGraphql(graphqlSchema, variables); return response.data.createTask; } );
步骤2:修改 TaskSlice
移除原有的异步 reducer,在 extraReducers 中处理 Thunk 的状态:
import { createSlice } from "@reduxjs/toolkit"; import { taskThunk, createTaskThunk } from "./thunks/task.thunk"; export const initialState: any = { tasks: [], status: "idle", error: null, }; const TaskSlice = createSlice({ name: "task", initialState, reducers: {}, // 移除原 createTask reducer extraReducers: (builder) => { builder .addCase(taskThunk.fulfilled, (state, actions) => { state.tasks = actions.payload.getTasks; state.status = "success"; state.error = null; }) .addCase(createTaskThunk.pending, (state) => { state.status = "loading"; state.error = null; }) .addCase(createTaskThunk.fulfilled, (state, actions) => { state.status = "success"; // 将新任务添加到数组 state.tasks.push(actions.payload); }) .addCase(createTaskThunk.rejected, (state, actions) => { state.status = "failed"; state.error = actions.error.message || "创建任务失败"; }); }, }); export default TaskSlice.reducer;
步骤3:更新组件调用
在 TaskCreatorForm 中 dispatch 新的 Thunk:
// 导入新的 Thunk import { createTaskThunk } from "../../../../redux/slices/tasks/thunks/task.thunk"; // 修改 createTaskHandle const createTaskHandle = () => { const payload = { taskName, taskTags, }; dispatch(createTaskThunk(payload)); };
4. 其他注意事项
- 确保
useGraphql返回的response.data.createTask是有效的任务对象,避免接口返回格式问题导致数据为 undefined; - 可以在组件中监听 Redux 的
status状态,展示加载提示或错误信息。
内容的提问来源于stack exchange,提问作者David Takidze
相关产品推荐
相关产品推荐

