@igorevi4oleg

Как корректно передать элемент в рендер?

Не могу понять логику отрисовки элемента в данном контексте:
Попытка TODO-List.
Я вписываю какой-то таск в инпут, добавляю его.
В этот таск рендерится элемент Clock, который возвращает дату и время на текущий момент.
Далее я вписываю следующий таск, добавляю его и React рендерит в него дату и время предыдущего таска, а предыдущему даёт новое значение... Почему так?
Соответственно и удаляет он нужный таск, но дату и время берёт только с конца. Почему элемент даты и время Clock не связывается с таском, в котором он был вызван, как пофиксить?
63c6db243b325963183076.png
import React from 'react';

class Clock extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      date: new Date(),
    };
  }

  render() {
    const { date } = this.state;

    return (
      <div>
        {date.toLocaleDateString()}, ({date.toLocaleTimeString()})
      </div>
    );
  }
}

export default Clock;

function ListItem({ itemName, onRemove }) {
  return (
    <>
      <div className="item">
        <div className="time__div">
          <Clock />
        </div>
        <div className="item__text">{itemName}</div>
        <div className="tools">
          <Checked key={itemName} />
          <Button
            name="X"
            onClick={() => onRemove(itemName)}
            customClass="item__remove__btn"
          />
        </div>
      </div>
    </>
  );
}

export default ListItem;

ниже код самого App.js
class App extends React.Component {
  constructor() {
    super();

    this.state = {
      key: 0,
      inputValue: '',
      todoList: [],
    };
  }

  onChangeInputValue = (event) => {
    this.setState({
      inputValue: event.target.value,
    });
  };

  onClickBtn = () => {
    const { inputValue, todoList } = this.state;

    this.setState({
      todoList: [inputValue, ...todoList],
      inputValue: '',
    });
  };

  onRemoveitem = (todoName) => {
    const { todoList } = this.state;

    const todoIndex = todoList.findIndex((str) => str === todoName);

    const newTodoList = [
      ...todoList.slice(0, todoIndex),
      ...todoList.slice(todoIndex + 1),
    ];

    this.setState({
      todoList: newTodoList,
    });
  };

  render() {
    const { inputValue, todoList } = this.state;

    return (
      <>
        <div className="input__button">
          <Input value={inputValue} onChange={this.onChangeInputValue} />

          <Button name="Add" onClick={this.onClickBtn} />
        </div>

        {todoList.map((itemString) => {
          return (
            <>
              <ListItem
                key={this.key}
                itemName={itemString}
                onRemove={this.onRemoveitem}
              />
            </>
          );
        })}
      </>
    );
  }
}

export default App;
  • Вопрос задан
  • 71 просмотр
Пригласить эксперта
Ответы на вопрос 1
@slide13
frontend/web-developer
Из того, что вижу я при беглом просмотре - у вас в качестве ключа в список ListItem передается undefined, т.к. у вас явно нет свойства key в текущем классе App (в консоли на это тоже ошибка должна быть). А так как ключи для всех элементов не заданы, то при добавлении в начало/середину списка нового элемента приводит к тому, что реакт неправильно высчитывает порядок элементов и из-за этого возникают такие странности при рендеринге списка.
В качестве решения должно сработать поставить в качестве ключа тоже itemString, если он у вас дублироваться не будет, конечно, но все же лучше при создании таска присваивать ему уникальный id, т.е. в todoList будет не просто массив текстов, а массив объектов, где каждый объект будет содержать id и текст таска. Тогда можно будет и тексты одинаковые добавлять для разных задач и удалять проще будет.
Также непонятно, для чего нужен key в стейте, если он не изменяется нигде.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
04 мая 2024, в 22:17
12000 руб./за проект
04 мая 2024, в 22:17
10000 руб./за проект
04 мая 2024, в 22:14
2000 руб./за проект