Предупреждение: flattenChildren (): обнаружены два дочерних элемента с одним и тем же ключом

Хорошо, я создаю простое приложение ToDo для учебных целей и получаю предупреждение, которое я не могу решить:

Когда я проверяю ToDo as Done, выдается ошибка. Я попытался установить ключ в качестве индекса каждого элемента, предупреждение прекратилось, но при обновлении списка был отображен дублированный элемент.

Вот мой компонент:

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;
    }
}

Остальной код здесь (GitHub)

Спасибо и извините за плохой английский!


person user3344570    schedule 03.01.2017    source источник


Ответы (1)


Проблема заключается в вашем редукторе. Вместо того, чтобы найти задачу, которую вы хотите завершить, и отредактировать ее завершенное значение, чтобы оно было истинным, вы добавляете копию указанного дела в конец вашего массива. Это заставляет ваше приложение пытаться отобразить все ваши задачи, даже если есть записи с одинаковым идентификатором (и тем же ключом).
Вы делаете это:
начальное состояние: [todo1: completed, todo2: not completed, todo3: completed] < br> конечное состояние: [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
      }
    )
}

Теперь вы можете изменить свое состояние в редукторе следующим образом:

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

Это должно помочь. Я также рекомендую хотя бы использовать Immutable.js в редукторах. Это упростило бы редактирование вашего состояния в большинстве случаев. Но это снова ваше дело, конечно.

person stinodes    schedule 03.01.2017
comment
Спасибо! Думаю, я до сих пор не понимаю, как работает Redux =) - person user3344570; 03.01.2017
comment
Что ж, всякий раз, когда запускается действие, вы редактируете свое состояние и возвращаете его. Я думаю, вы понимаете эту часть. Вы только что неправильно отредактировали свое состояние. Вам НЕ ОБЯЗАТЕЛЬНО использовать деструктуризацию массива как таковую (часть [...state, {}]). Вы можете просто написать это так, как вам удобно, если вы избегаете побочных эффектов. - person stinodes; 03.01.2017