Анализ поведения React‑компонента ReviewMe и проверка добавления задач

Клик использует актуальное замыкание, а глобальный Enter — данные первого рендера. Объедините оба действия через submit формы, уберите document-слушатель и считайте задачи по items.length.

Короткий ответ

Что ответить на собеседовании

Клик использует актуальное замыкание, а глобальный Enter — данные первого рендера. Объедините оба действия через submit формы, уберите document-слушатель и считайте задачи по items.length.

Подробный разбор

Ответ с пояснениями

Условие

Необходимо сформировать вывод о том, как работает данный компонент, какие задачи он решает и какие потенциальные недостатки могут возникнуть. Особое внимание уделите логике добавления новых задач как при нажатии клавиши Enter, так и при клике по кнопке.

import React from "react";

const ReviewMe = () => {
  const [inputValue, setInputValue] = React.useState('');
  const [items, setItems] = React.useState([]);
  const [counter, setCounter] = React.useState(1);

  React.useLayoutEffect(() => {
    const handler = (event) => {
      if (event.keyCode === 13) {
        createTask(inputValue);
      }
    };
    document.addEventListener("keydown", handler);
    // Note: no cleanup, which may cause a memory leak on re‑renders.
  }, []);

  const createTask = React.useCallback((text) => {
    const newTask = { id: counter, text };
    setItems([...items, newTask]);
    setCounter(counter + 1);
    setInputValue('');
  });

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="Enter a new task"
      />
      <button onClick={() => createTask(inputValue)}>Add Task</button>
      <div>
        {items.map((task) => (
          <div key={task.id}>{task.text}</div>
        ))}
      </div>
      <p>Total Tasks: {counter}</p>
    </div>
  );
};

export default ReviewMe;

В описании следует указать, что компонент позволяет вводить текст задачи, сохранять её в массив и отображать список. Нужно проверить, что задача добавляется при нажатии Enter и при клике на кнопку, а также обратить внимание на возможные проблемы: отсутствие очистки обработчика события, использование useLayoutEffect без необходимости, отсутствие зависимостей в useCallback, потенциальные баги с замыканиями при обновлении состояния.

Ответ

Клик использует актуальное замыкание, а глобальный Enter — данные первого рендера. Объедините оба действия через submit формы, уберите document-слушатель и считайте задачи по items.length.

const [inputValue, setInputValue] = React.useState('');
const [items, setItems] = React.useState([]);
const nextId = React.useRef(1);
const createTask = event => {
  event.preventDefault();
  const text = inputValue.trim();
  if (!text) return;
  const task = { id: nextId.current++, text };
  setItems(previous => [...previous, task]);
  setInputValue('');
};
return <form onSubmit={createTask}>
  <input value={inputValue} onChange={e => setInputValue(e.target.value)} />
  <button type="submit">Add Task</button>
  {items.map(task => <div key={task.id}>{task.text}</div>)}
  <p>Total Tasks: {items.length}</p>
</form>;

Эти строки заменяют тело компонента. Исходный useCallback без массива не стабилизирует функцию. Слушатель с [] не добавляется на каждом рендере, но остаётся после размонтирования без cleanup и хранит устаревшие items/counter/inputValue. useLayoutEffect здесь вообще не нужен.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее