更改现有对象的状态

时间:2020-03-05 11:53:48

标签: javascript reactjs state

您好,我正在使用React上下文,但是遇到了问题。

我拥有包含所有逻辑的组件:

import React , {useContext} from 'react';
import {TodoContext} from '../../contexts/todo-context';
import Todo from './Todo'; 
import './Todos.css';

export default function TodoList() {
    const [todos , setTodos] = useContext(TodoContext);

    const markComplete = (e) => {
       setTodos(prevState => [...prevState , {...e.target.value , done:true} ]); 
       console.log(todos);
    }


    return (
        <div className="TodoContainer">
            {todos.map(todo => (<Todo key={todo.id} todo={todo} markComplete={markComplete} /> ))}
        </div>
    )
}

我正在传递一个markComplete函数,该函数将在Todo组件中使用。

Todo组件:

从“反应”导入React

export default function Todo({todo , markComplete}) {
    return (
        <div>
            <input type="checkbox" value={todo} onChange={markComplete}></input>
            <li>{todo.title}</li>
            <div className="spacer"></div>
        </div>
    )
}

在这里,我有一个复选框,其中onChange应该会触发我的markComplete函数。这行得通,但是markComplete函数由于某种原因不会改变我的状态。再次是该功能:

const markComplete = (e) => {
   setTodos(prevState => [...prevState , {...e.target.value , done:true} ]); 
   console.log(todos);
}

它还会生成一条错误消息,提示我应将密钥传递给我(我已经在这样做了)

状态:

const [todo, setTodo] = useState([
    {
        title : 'Do the dishes', 
        done : false , 
        id: 123 
    },
    {
        title : 'wash car', 
        done : false , 
        id: 423 
    },
    {
        title : 'Buy pen', 
        done : false , 
        id: 323 
    }
]); 

1 个答案:

答案 0 :(得分:1)

更新状态的方法是错误的。

请注意,您在待办事项中做到了:

<input type="checkbox" value={todo} onChange={markComplete}></input>

todo本身是一个对象,这意味着在执行此操作时:

setTodos(prevState => [...prevState , {...e.target.value , done:true} ]); 

您基本上错误地散布了该物体。实际上,下一个状态更新的结果是更新:

0: {title: "Do the dishes", done: false, id: 123}
1: {title: "wash car", done: false, id: 423}
2: {title: "Buy pen", done: false, id: 323}
3: {0: "[", 1: "o", 2: "b", 3: "j", 4: "e", 5: "c", 6: "t", 7: " ", 8: "O", 9: "b", 10: "j", 11: "e", 12: "c", 13: "t", 14: "]", done: true}

这说明了您遇到的unique key错误。

一种可能的解决方案是对更改处理程序使用包装,该包装传递项目ID和已检查状态:

function Todo({todo , markComplete}) {
    const handleChange = React.useCallback(e => {
        markComplete(todo.id, e.target.checked);
    }, [todo, markComplete]);

    return (
        <div>
            <input type="checkbox" value={todo.id} onChange={handleChange}></input>
            <li>{todo.title}</li>
            <div className="spacer"></div>
        </div>
    )
}

markComplete:

const markComplete = (id, checked) => {
   setTodos(prevState => prevState.map(it => it.id === id ? ({ ...it, done: checked }) : it));
}

我还建议在上述功能中使用useCallback

这是一个小提琴:https://jsfiddle.net/vdzbj16a/