I'm currently learning hook, and I'm writing a todo-list:
import './App.css';
import React, {useState} from 'react';
import Item from './components/Item';
function App() {
const [tasks, setTasks] = useState([]);
const addTask = (e) => {
if(e.key === 'Enter'){
let newTask = {content: e.target.value, completed: false};
console.log(newTask);
setTasks(prevTask => {
return ([...prevTask, newTask]);
});
console.log(tasks);
}
}
const completeTask = (e) =>{
let newTask = tasks.slice();
newTask[e].completed = !tasks[e].completed;
setTasks(newTask);
}
const deleteTask = (e) => {
let newTask = tasks.slice();
newTask.splice(e);
setTasks(newTask);
}
return (
<>
<header className="todo-app__header">
<h1 className="todo-app__title">todos</h1>
</header>
<section className="todo-app__main">
<input className="todo-app__input" placeholder="What needs to be done?" onKeyDown={addTask}/>
<ul className="todo-app__list" id="todo-list">
{tasks.map(item => <Item num = {tasks.indexOf(item)} text={item.content} completed = {item.completed}
onClick = {completeTask(tasks.indexOf(item))} delete = {deleteTask(tasks.indexOf(item))}/>)}
</ul>
</section>
</>
);
}
export default App;
However, adding tasks is not working!! The newTask printed is well, but it doesn't push into the tasks array. The tasks is still empty.
What's the problem?
Also, another problem: is it related to useeffect
? I don't know what useeffect
is used for.
CodePudding user response:
The issue is that every time your component renders, it executes both completeTask
and deleteTask
, because you are using function calls as props. You need to be passing in a function object or expression. Instead of telling the component to execute completeTask
on click, the function call just executes it right there as soon as the component is rendered.
The problem is with this part of your code:
<ul className="todo-app__list" id="todo-list">
{tasks.map(item => <Item num = {tasks.indexOf(item)} text={item.content} completed = {item.completed}
onClick = {completeTask(tasks.indexOf(item))} delete = {deleteTask(tasks.indexOf(item))}/>)}
</ul>
The following lines:
delete = {deleteTask(tasks.indexOf(item))}
onClick = {completeTask(tasks.indexOf(item))}
Should be changed to:
delete = {() => deleteTask(tasks.indexOf(item))}
onClick = {() => completeTask(tasks.indexOf(item))}
In normal HTML, it would look like delete="deleteFunction()"
, but in React, it should be delete={deleteFunction}
, because writing a function with parenthesis after it is a function call, not a function expression. If you need to pass in an argument, you can either pass the argument in as a prop on the component, or change the line to delete={() => deleteFunction(arg)}
, as the parenthesis and arrow makes it a function expression.
See Handling Events: https://reactjs.org/docs/handling-events.html
CodePudding user response:
Your code works well and there is no problem.
React setState
action in async. Try to log it in useEffect
.
const App = () = => {
const [tasks, setTasks] = useState([]);
useEffect(() => {
console.log(tasks)
}, [tasks]);
const addTask = () => {
const newTask = {...};
setTasks([...tasks, newTask]);
}
}
CodePudding user response:
Here as I can see, you are doing console.log(tasks)
in the same function.
Try the console.log(tasks)
outside function and you will see tasks
array with the values you entered.
CodePudding user response:
there is no problem
import React, {useState} from 'react';
function Add() {
const [tasks, setTasks] = useState([]);
const addTask = (e) => {
if(e.key === 'Enter'){
let newTask = {content: e.target.value, completed: false};
console.log(newTask);
setTasks(prevTask => {
return ([...prevTask, newTask])
});
console.log(tasks);
}
}
const completeTask = (e) =>{
let newTask = tasks.slice();
newTask[e].completed = !tasks[e].completed;
setTasks(newTask);
}
const deleteTask = (e) => {
let newTask = tasks.slice();
newTask.splice(e);
setTasks(newTask);
}
return (
<>
<header className="todo-app__header">
<h1 className="todo-app__title">todos</h1>
</header>
<section className="todo-app__main">
<input className="todo-app__input" placeholder="What needs to be done?" onKeyDown={addTask}/>
<ul className="todo-app__list" id="todo-list">
{tasks.map((item)=> <li>{item.content}</li>)}
</ul>
</section>
</>
);
}
export default Add;
it works very well and that means your Item component is your problem.