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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 18:39:58