为了try 和理解Redux,我设置了一个简单的TODO项目.不幸的是,我无法让useDispatch人go 工作.

我可以获得我用useSelect存储的所有待办事项,但我不能添加一个待办事项,因为我认为useDispatch会导致错误.

错误显示:"e.preventDefault()不是一个函数",但当我删除useDispatch时,它不会显示此错误,因此我认为错误来自useDispatch.

以下是切面:

import { createSlice } from "@reduxjs/toolkit";

const slice = createSlice({
  name: "list",
  initialState: {
    value: [
      {
        id: 0,
        label: "Boodschappen",
      },
      {
        id: 1,
        label: "Scheren",
      },
      {
        id: 2,
        label: "Stoep vegen",
      },
    ],
  },
  reducers: {
    addTodo: (state, action) => {
      state.list = action.payload;
    },
  },
});

export const { addTodo } = slice.actions;

export default slice.reducer;

以下是表单组件:

import { useDispatch, useSelector } from "react-redux";
import { addTodo } from "../../slices/todoSlice";

function Form() {
  const list = useSelector((state) => state.list.value);
  const [todo, setTodo] = useState("");

  const dispatch = useDispatch();

  const addTodo = (e, addTodo) => {
    e.preventDefault();
    dispatch(addTodo([...list, { id: list.length + 1, label: todo }]));

    setTodo("");
  };

  return (
    <div>
      <FormWrapper>
        <form action="" onSubmit={(e) => addTodo(e, addTodo)}>
          <input
            type="text"
            name="todo"
            id="todo"
            value={todo}
            onChange={(e) => setTodo(e.target.value)}
          />
          <input type="submit" value="Add todo" />
        </form>
      </FormWrapper>
    </div>
  );
}

这就是我准备好的store .我确实把它包在了我的应用程序组件上:

import { configureStore } from "@reduxjs/toolkit";
import listReducer from "../slices/todoSlice";

// config the store
const store = configureStore({
  reducer: {
    list: listReducer,
  },
});

// export default the store
export default store;

推荐答案

代码并没有像你想象的那样发送addTodo.不是将导入的addTodo操作传递给本地addTodo提交处理程序函数,而是将本地addTodo提交处理程序传递给自身并在dispatch中调用,并在随后的调用中传递一个不是要调用preventDefault的事件对象的参数.

...
import { addTodo } from "./list.slice"; // <-- never referenced

function Form() {
  const list = useSelector((state) => state.list.value);
  const [todo, setTodo] = useState("");

  const dispatch = useDispatch();

  const addTodo = (e, addTodo) => { // <-- (1) this addTodo is in scope
    e.preventDefault();
    dispatch(addTodo( // <-- (3) calls local addTodo without event object!
      [...list, { id: list.length + 1, label: todo }]
    ));

    setTodo("");
  };

  return (
    <div>
      <FormWrapper>
        <form action="" onSubmit={(e) => addTodo(e, addTodo)}> // <-- (2) addTodo passed to itself!
          <input
            type="text"
            name="todo"
            id="todo"
            value={todo}
            onChange={(e) => setTodo(e.target.value)}
          />
          <input type="submit" value="Add todo" />
        </form>
      </FormWrapper>
    </div>
  );
}

修复很简单,将提交处理程序重命名为anything,但与您想要分派的操作具有相同的标识符.您也不需要通过提交处理程序回调的参数来传递操作,因为addTodo操作已经具有文件作用域.

...
import { addTodo } from "./list.slice";

function Form() {
  const list = useSelector((state) => state.list.value);
  const [todo, setTodo] = useState("");

  const dispatch = useDispatch();

  const submitHandler = (e) => {
    e.preventDefault();
    dispatch(addTodo( // <-- imported addTodo action :)
      [...list, { id: list.length + 1, label: todo }]
    ));

    setTodo("");
  };

  return (
    <div>
      <FormWrapper>
        <form action="" onSubmit={submitHandler}>
          <input
            type="text"
            name="todo"
            id="todo"
            value={todo}
            onChange={(e) => setTodo(e.target.value)}
          />
          <input type="submit" value="Add todo" />
        </form>
      </FormWrapper>
    </div>
  );
}

Javascript相关问答推荐

使用JavaScript更改json值顺序

带对角线分隔符的图像滑动器

如何在alpinejs中显示dev中x-for的元素

在卡信息之间切换

如何通过继承contentitable属性的元素捕捉keydown事件?

在NextJS中使用计时器循环逐个打开手风琴项目?

主要内部的ExtJS多个子应用程序

如何避免移动设备中出现虚假调整大小事件?

zoom svg以适应圆

我可以从React中的出口从主布局调用一个处理程序函数吗?

D3 Scale在v6中工作,但在v7中不工作

如何在Angular17 APP中全局设置AXIOS

单个HTML中的多个HTML文件

如何将innerHTML字符串修剪为其中的特定元素?

在开发期间,Web浏览器如何运行&qot;.jsx&qot;文件?

在FAQ Accodion应用程序中使用React useState时出现问题

SPAN不会在点击时关闭模式,尽管它们可以发送日志(log)等

<;img>;标记无法呈现图像

处理app.param()中的多个参数

是否设置以JavaScript为背景的画布元素?