[英]Can't update value using reducer React JS after click
I'm currently learning useReducer and try to convert useState to useReducer in todo app.我目前正在学习 useReducer 并尝试在 todo 应用程序中将 useState 转换为 useReducer。 My problem :
我的问题 :
// First try
case TOGGLE_TODO:
let targetId = todoItem[action.index];
let newTodo = [...todoItem];
return (newTodo[targetId].completed = !newTodo[targetId].completed);
// Second try
case TOGGLE_TODO:
return todoItem.map((todo, index) => {
if (index === action.index) {
return { ...todo, completed: !todo.completed };
}
return todo;
});
<button
value={index}
onClick={(event) =>
dispatch({
type: TOGGLE_TODO,
index: event.target.value,
})
}
>
{todo.completed ? "done" : "pending"}
</button>
const onUpdate = (e) => {
const target = e.currentTarget.value;
const todoTarget = todoItem[target].name;
setInput(todoTarget);
setTodoIndex(target);
};
And here is my codesandbox for full code.这是我的完整代码的代码框。 MY CODE USING USESTATE and MY CODE USING USEREDUCER
我的代码使用 USESTATE和我的代码使用 USEREDUCER
First, you first TOGGLE_TODO handler if flawed -首先,如果有缺陷,您首先要使用 TOGGLE_TODO 处理程序 -
// First try
case TOGGLE_TODO:
let targetId = todoItem[action.index];
let newTodo = [...todoItem];
return (newTodo[targetId].completed = !newTodo[targetId].completed);
Your todoAction
is actually a reducer and not an action, so you should rename it to todoReducer
.你的
todoAction
实际上是一个 reducer 而不是一个动作,所以你应该把它重命名为todoReducer
。 Also, a reducer needs to return a new copy of the entire state, and not just change one part of it, so your second try is correct.此外,reducer 需要返回整个状态的新副本,而不仅仅是更改其中的一部分,因此您的第二次尝试是正确的。
case TOGGLE_TODO:
return todoItem.map((todo, index) => {
if (index === action.index) {
return { ...todo, completed: !todo.completed };
}
return todo;
});
Notice how in the first case you are returning one todoItem, where in the second case you are returning an entire new array.请注意,在第一种情况下,您将返回一个 todoItem,而在第二种情况下,您将返回一个全新的数组。
The problem with the code is that in your button, when you dispatch the action with the value, you are dispatching a string -代码的问题在于,在您的按钮中,当您发送带有值的操作时,您正在发送一个字符串 -
<button
value={index}
onClick={(event) =>
dispatch({
type: TOGGLE_TODO,
index: event.target.value, // <- This is a string
})
}
>
{todo.completed ? "done" : "pending"}
</button>
And in your reducer you are trying to compare it to a number -在你的减速器中,你试图将它与一个数字进行比较 -
if (index === action.index) // This will always be false since index is a .number and action.index is a string
The solution is to dispatch a number like so -解决方案是发送一个这样的号码 -
dispatch({
type: TOGGLE_TODO,
index: Number(event.target.value),
})
working codesandbox - https://codesandbox.io/s/long-monad-5yzjv7?file=/src/App.js工作代码框 - https://codesandbox.io/s/long-monad-5yzjv7?file=/src/App.js
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.