警告:flattenChildren(...):遇到两个 children 具有相同的键

Warning: flattenChildren(...): Encountered two children with the same key

好的,我正在构建一个简单的 ToDo 应用程序用于学习目的,我面临着一个我无法解决的警告:

当我将 ToDo 检查为完成时,抛出错误。我尝试将键设置为每个元素的索引,警告停止了,但是列表更新时呈现了重复的元素。

这是我的组件:

import React from "react";
import TodoTask from "./TodoTask";

const TodoList = ({todos, onTaskCheck}) => {

    function renderList() {
        return (
            todos.map((todo) => {
                return <TodoTask key={todo.id} todo={todo} onTaskCheck={onTaskCheck} />
            })
        );
    }

    return (
        <div>
            <h1 className="title is-4">ToDo List</h1>
            <ul className="task-list">
                {renderList()}
            </ul>
        </div>
    );
};

export default TodoList;

这是减速器:

export default function TodoReducers(state = [], action) {
    switch(action.type) {
        case "LIST_TODOS":
            return [
                {id: 1, description: "Task 1", isCompleted: true},
                {id: 2, description: "Task 2", isCompleted: true},
                {id: 3, description: "Task 3", isCompleted: true},
                {id: 4, description: "Task 4", isCompleted: false},
                {id: 5, description: "Task 5", isCompleted: false}
            ];
        case "CHECK_TODO":
            return [...state, Object.assign({}, action.payload, action.payload.isCompleted = true)];
        default:
            return state;
    }
}

The rest of the code is here (GitHub)

谢谢,抱歉英语不好!

问题出在你的reducer。您不是找到要完成的待办事项并将其完成的值编辑为 true,而是将所述待办事项的副本附加到数组的末尾。这会使您的应用尝试呈现所有待办事项,即使存在具有相同 ID(和相同键)的条目。
您正在这样做:
初始状态:[todo1: completed, todo2: not completed, todo3: completed]
最终状态: [todo:1 completed, todo2: not completed, todo3: completed, todo2: completed]
但这不是我们想要的。

我通过遍历你的待办事项解决了你的问题,找到你想要完成的并修改那个。
我将此功能添加到与您的减速器相同的文件中(当然,您可以根据需要实现它)。

function completeTodo(todos, id) {
  return todos
    .map(
      todo => {
        if (todo.id === id)
          todo.isCompleted = true
        return todo
      }
    )
}

现在您可以像这样在 reducer 中修改状态:

   case "CHECK_TODO":
            return completeTodo(state, action.payload.id)

这应该可以解决问题。我还建议至少在你的减速器中使用 Immutable.js 。很多时候,它会使编辑状态变得更简单。当然,这又取决于你。