Ввод React сохраняет ввод при первом щелчке, а затем показывает его в пользовательском интерфейсе при втором щелчке... ПОЧЕМУ?!!! и как это исправить

Я делаю приложение списка задач с реакцией, и я столкнулся с такой ошибкой, когда вы вводите ввод, затем нажимаете кнопку, чтобы создать новый объект todoItem, он показывает пустой объект, а затем сохраняет этот ввод в объектной переменной todoList внутри производства код, то этот первый элемент todo появляется в пользовательском интерфейсе при 2-м щелчке, а при 3-м щелчке появляется 2-й элемент todoItem, 4-й щелчок по 3-му элементу и так далее... я не знаю, почему это происходит, и я хочу решить это, здесь это мой код, ребята:

----------APP COMPONENT-------
import React, { useState } from "react";
import Form from "./Form";
import List from "./List";

function App() {
  const [input, setInput] = useState("");
  const [todoItem, setTodoItem] = useState({});
  const [todoList, setTodoList] = useState([]);

  const addTodoItem = (e) => {
    e.preventDefault();
    input && setTodoItem({ content: input, id: Math.random() * 1000 });
    setTodoList([...todoList, todoItem]);
    setInput("");
  };

  return (
    <div>
      <Form input = {input} addTodoItem = {addTodoItem} setInput = {setInput} />
      <List todoList = {todoList} setTodoList = {setTodoList} />
    </div>
  );
}

export default App;

---------FORM COMPONENT-----------
import React from "react";

function Form({ input, setInput, addTodoItem }) {
  return (
    <div>
      <form action = "">
        <label>todos</label>
        <input
          value = {input}
          onChange = {(e) => setInput(e.target.value)}
          placeholder = "what needs to be done"
          type = "text"
        />
        <button onClick = {addTodoItem}>set todo</button>
      </form>
    </div>
  );
}
export default Form;


----------LIST COMPONENT-----------
import React, { useState } from "react";

function List({ setTodoList, todoList }) {
  const [completed, setCompleted] = useState(false);

  const deleteItem = (del) => {
    todoList?.map((item, i, arr) => {
      setTodoList(arr.filter((value) => value.id != del));
      console.info("item>>>", item, "index>>>>", i, "array>>>>", arr);
    });
  };
  const reverseCompleted = () =>
    completed ? setCompleted(false) : setCompleted(true);
  return (
    <div>
      <div>
        {todoList.map((item, i) => (
          <div key = {i}>
            <p>{item.content}</p>
            <button onClick = {() => deleteItem(item.id)}>Delete</button>
            <button onClick = {reverseCompleted}>
              {completed ? "unCompleted" : "Completed"}
            </button>
          </div>
        ))}
      </div>
    </div>
  );
}

export default List;
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
122
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Контент при первой попытке пуст, потому что обновление useState React не происходит немедленно. Таким образом, вам каким-то образом придется дождаться изменения todoItem, чтобы поместить его в массив todoList.

Одним из возможных решений может быть использование useEffect React и отслеживание изменений на todoItem. И когда он изменится и его свойство content не будет пустым, вы можете обновить todoList:

useEffect(() => {
  if (todoItem.content) {
    setTodoList([...todoList, todoItem]);
  }
}, [todoItem]);

const addTodoItem = (e) => {
  e.preventDefault();
  input && setTodoItem({ content: input, id: Math.random() * 1000 });
  setInput("");
};

Это решение может оказаться подверженным ошибкам, потому что всякий раз, когда ссылка todoItem изменяется, она будет добавляться к todoList, а это не то, что вам нужно.

Другое, лучшее решение, которое я бы посоветовал, — это объявить новую переменную внутри обработчика addTodoItem и добавить ее в массив todoList, а также вызвать setTodoList:

const addTodoItem = (e) => {
  e.preventDefault();
  const newTodoItem = { content: input, id: Math.random() * 1000 };
  input && setTodoItem(newTodoItem);
  setTodoList([...todoList, newTodoItem]);
  setInput("");
};

но одна вещь, которую я не понял, это то, почему вы создаете переменную newTodItem, почему бы не напрямую setTodoItem({content: input, id: Math.random() * 1000}) какая разница, не одно и то же? @Капобайза

MansouriAla 26.12.2020 21:55

@MansouriAla Я объявляю переменную newTodoItem, потому что вы можете мгновенно использовать ее обновленное значение в двух функциях: setTodoItem и setTodoList. Принимая во внимание, что если вы использовали переменную todoItem, вам нужно дождаться, пока ее значение будет обновлено хуком setTodoItemuseState, прежде чем использовать его. input && setTodoItem({ content: input, id: Math.random() * 1000 }); после выполнения этой строки значение todoItem по-прежнему остается пустым объектом, {}. Поэтому, когда выполняется следующая строка: setTodoList([...todoList, todoItem]);, она устанавливает пустой объект в массиве.

Kapobajza 28.12.2020 10:47

Да, теперь я вижу, я помню, что useState не выполняется мгновенно, поэтому следующее значение будет принимать пустой объект, большое спасибо за объяснение, ценю это, теперь я понимаю

MansouriAla 28.12.2020 22:18

Другие вопросы по теме