Я делаю приложение списка задач с реакцией, и я столкнулся с такой ошибкой, когда вы вводите ввод, затем нажимаете кнопку, чтобы создать новый объект 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;
Контент при первой попытке пуст, потому что обновление 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("");
};
@MansouriAla Я объявляю переменную newTodoItem
, потому что вы можете мгновенно использовать ее обновленное значение в двух функциях: setTodoItem
и setTodoList
. Принимая во внимание, что если вы использовали переменную todoItem
, вам нужно дождаться, пока ее значение будет обновлено хуком setTodoItem
useState
, прежде чем использовать его. input && setTodoItem({ content: input, id: Math.random() * 1000 });
после выполнения этой строки значение todoItem
по-прежнему остается пустым объектом, {}
. Поэтому, когда выполняется следующая строка: setTodoList([...todoList, todoItem]);
, она устанавливает пустой объект в массиве.
Да, теперь я вижу, я помню, что useState не выполняется мгновенно, поэтому следующее значение будет принимать пустой объект, большое спасибо за объяснение, ценю это, теперь я понимаю
но одна вещь, которую я не понял, это то, почему вы создаете переменную newTodItem, почему бы не напрямую setTodoItem({content: input, id: Math.random() * 1000}) какая разница, не одно и то же? @Капобайза