React useReducer 不更新数组中的对象

React useReducer not updating object in array

待办事项组件:

import React, { useReducer, useState } from 'react';
import Todo2 from './Todo2';

export const ACTIONS = {
    ADD_TODO : 'add-todo',
    TOGGLE_TODO : 'toggle-todo'
};

function reducer(state, action) {
    switch(action.type) {
        case ACTIONS.ADD_TODO:
            return [...state, {id: Date.now(), name: action.payload.name, complete: false}];
        case ACTIONS.TOGGLE_TODO:
            const patch = [...state];

            console.log('The index is:', action.payload.index);
            console.log('The current state is:', patch[action.payload.index].complete);

            // update state
            patch[action.payload.index].complete = !patch[action.payload.index].complete;

            console.log('The updated state is:', patch[action.payload.index].complete);
            console.log('The patch is:', patch);
            return patch;
    }
}
export default function Todos() {
    const [todos, dispatch] = useReducer(reducer, []);
    const [name, setName] = useState('');

    function handleSubmit(e) {
        e.preventDefault();

        dispatch({type: ACTIONS.ADD_TODO, payload: {name: name}});
        setName('');
    }
    return (
        <div>
            <form onSubmit={handleSubmit}>
                <input type="text" value={name} onChange={e => setName(e.target.value)}/>
            </form>
            {todos.map((todo, i) => <Todo2 key={todo.id} todo={todo} index={i} dispatch={dispatch} />)}
        </div>
    );
}

待办事项组件:

import React from 'react';
import { ACTIONS } from './Todos2';

export default function Todo2({ todo, dispatch, index }) {
    return (
        <div>
            <span style={{color: todo.complete ? 'green':'red' }}>{todo.name}</span>
            <button onClick={e => dispatch({type: ACTIONS.TOGGLE_TODO, payload : {index: index}})}>Toggle</button>
        </div>
    )
}

我正在尝试更新数组中的对象,根据其当前值将其“完整”属性 设置为 true 或 false。我 console.logged 结果,但最后补丁永远不会得到它的更新数据,它总是保留它的原始值。

如果我像这样更新状态,它会起作用,但我不知道为什么会起作用,但更新索引的方式不起作用。

// update state
patch[action.payload.index].complete = true;

我创建了一个 codesandbox 示例并重现了同样的问题,然后我将 const patch = [...state] 更改为:

import _ from 'lodash'
...
...
const patch = _.cloneDeep(state)

而且,其他一切都保持不变,它就像一个魅力。这是 code 现在我知道,传播运算符 ... 确实创建了一个 浅拷贝 而不是 深拷贝 .因此,我认为您的 !patch[action.payload.index].complete 在同一行中更新,创建了一个矛盾的分配(如双重更新)。找不到技术参考来更好地解释这一点,但问题肯定是没有深度复制对象。

建议

case ACTIONS.TOGGLE_TODO:
   return state.map((el, idx) => idx === action.payload.index ? {...el, complete: !el.complete} : el)