在React应用程序中,我试图将+1增加到数组中每个对象的id字段。
function App() {
const[todos, setTodos] = useState([
{
id: 1,
title: 'Take out the trash',
completed: false
},
{
id: 2,
title: 'Dinner',
completed: false
},
{
id: 3,
title: 'Meeting with boss',
completed: false
}
]);
function onClick(){
setTodos(todos => todos.map(todo => todo.id = todo.id + 1))
}
return (
<div className="App">
<div className="todo-list">
<ul>
{todos.map(todo => <li>{todo.id},{todo.title},{String(todo.completed)}</li>)}
</ul>
<button onClick={()=>onClick()}
>Update
</button>
</div>
</div>
);
}
在页面的初始渲染中,对象列表正确显示。首次单击按钮时,它们将更改为:
,,undefined
,,undefined
,,undefined
在第3次点击此错误:
TypeError: Cannot create property 'id' on number '2'
我想念地图功能吗?
答案 0 :(得分:4)
function onClick(){
setTodos(todos => todos.map(todo => todo.id = todo.id + 1))
}
您要从地图函数返回todo.id
,因此将待办事项设置为ID为[2, 3, 4]
的数组。然后,当您尝试访问todo.id
时,它是undefined
,因为number.id
是未定义的`。
您还可以通过说todo.id = ...
来改变状态。如果在设置状态时发现自己使用分配操作器(=
),则可能是做错了什么。您不应该拥有state = ...
。
您想要执行以下操作:
function onClick(){
setTodos(prev => prev.map(t => ({ ...t, id: t.id + 1 })))
}
在创建阴影变量名称时,我也将todos
重命名为prev
。
答案 1 :(得分:1)
您实际上并没有在其中返回新的todo实体,而只是返回了id
属性,那是一个错误。解决方法是
function onClick(){
setTodos(todos => todos.map(todo => ({ ...todo, id: todo.id + 1 })))
}
:)
答案 2 :(得分:1)
Map函数迭代到每个值,并返回您在迭代器中计算出的映射值。
您的代码将待办事项对象数组转换为递增的待办事项ID数组,例如[2,3,4]
,因此,当您的下一个map方法运行时,它将给出您面临的错误。第一次,您的地图将对象转换为整数。
您应该更新地图方法,例如:todos.map(todo => ({...todo, id: todo.id + 1}))
注意:同样,您也不需要在setTodos挂钩中写入todos =>
。
答案 3 :(得分:0)
您的map
函数不会返回对象,但是我认为您应该使用reduce
JavaScript函数
function onClick() {
const reducerFunction = (r, v) => r.concat({ ...v, id: v.id + 1 })
setTodos(
todos.reduce(reducerFunction, [])
);
}
我还认为您应该尝试使用useReduce挂钩,这样可以使解决方案更加简洁。
useState的替代方法。接受类型的变径(状态,动作) => newState,并返回与调度方法配对的当前状态。 (如果您熟悉Redux,您已经知道 有效。)
当您遇到复杂的情况时,useReducer通常比useState更可取 涉及多个子值或下一个状态的状态逻辑 取决于前一个。 useReducer还可以让您优化 触发深层更新的组件的性能,因为您可以 向下传递调度而不是回调。