i am making a simple to do list, yet in that there is some error on remove button and its action, if i dont add any function regarding remove list, everything is working fine...
here is my code:
ToDo.js
import React, { useState } from 'react'
import AddNew from './Addnew';
import ToDoList from './ToDoList';
function Todo() {
const[toDoList, setToDoList] = useState([]);
function addNew(addText, date){
// console.log(addText);
// console.log(date);
const obj = {
text : addText,
expiry : date,
completed : false
}
const newToDo = [...toDoList, obj];
setToDoList(newToDo);
// console.log(toDoList);
}
function handleCheck(index){
const newToDOs = [...toDoList];
if(toDoList[index].completed==false){
newToDOs[index].completed = true;
}
else {
newToDOs[index].completed = false;
}
setToDoList(newToDOs);
}
function RemoveList(index){
console.log(index);
const newTo = [...toDoList];
newTo.splice(index,1);
setToDoList(newTo);
}
return (
<>
<h1>To Do List</h1>
<AddNew addNew={addNew}/>
<ul className="list-group">
<ToDoList list={toDoList} handleCheck={handleCheck} RemoveList={RemoveList} />
</ul>
</>
);
}
export default Todo;
ToDoList.js
import React from "react";
function ToDoList(props) {
return (
<>
{/* {props.list.length == 0 ? <h3>To Do List is Empty</h3> : null} */}
{props.list.map((element, index) => {
return (
<>
<li
className={
element.completed
? "list-group-item yes-comp"
: "list-group-item no-comp"
}
>
<span className="badge text-bg-info">{index 1}</span>  
<input
type="checkbox"
defaultChecked={element.completed}
onChange={() => {
props.handleCheck(index);
}}
/>{" "}
 
{element.text}
<span className="badge text-bg-light">
{element.expiry.toString().slice(4, 15)}
</span>
<button className="btn btn-danger" onChange={props.RemoveList(index)} >Remove</button>
</li>
</>
);
})}
</>
);
}
export default ToDoList;
AddNew.js
import React, { useState } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
function AddNew(props) {
const [startDate, setStartDate] = useState(new Date());
const [input, setInput] = useState("");
function submitData() {
props.addNew(input, startDate);
setInput("");
}
return (
<>
<div className="Container InputContain">
<input className="form-control" placeholder="Add New in To Do List" value={input} onInput={(e) => setInput(e.target.value)} />
<div>
<DatePicker
className="AddDate"
selected={startDate}
onChange={(date) => setStartDate(date)}
/>
<button className="btn btn-primary btn-cust" onClick={submitData}>Add</button>
</div>
</div>
</>
);
}
export default AddNew;
the warnings are:
react-dom.development.js:86 Warning: Cannot update a component (`Todo`) while rendering a different component (`ToDoList`). To locate the bad setState() call inside `ToDoList`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
at ToDoList (http://localhost:3000/static/js/bundle.js:262:21)
at ul
at Todo (http://localhost:3000/static/js/bundle.js:374:82)
at App
react-jsx-dev-runtime.development.js:87 Warning: Each child in a list should have a unique "key" prop.
Check the render method of `ToDoList`. See https://reactjs.org/link/warning-keys for more information.
at ToDoList (http://localhost:3000/static/js/bundle.js:262:21)
at ul
at Todo (http://localhost:3000/static/js/bundle.js:374:82)
at App
i tried to change my function name, change method on how to remove from list and everything that i could find on google, yet not working!
CodePudding user response:
Without running the code, I believe your issue is this line of code:
<button className="btn btn-danger" onChange={props.RemoveList(index)} >Remove</button>
Event handlers should always be passed a call-back function to be stored in memory for when the event happens. Also, this event handler should be an onClick
. Your onClick
atribute should look like this:
onClick={() => props.RemoveList(index)}
As a side note, passing a function call to an event handler only works if the function being called returns a function itself and has no side-effects:
const getCallback = () => {
const callback = () => setState('foo');
return callback;
}
<button onClick={GetCallback()}> set state </button>
Hope this helps.
CodePudding user response:
You'll want to fire the remove function from onClick()
, not onChange()
. Another thing is, that when you pass the reference to the onClick
, such as onClick={props.RemoveList(index)}
, the onClick event calls the removeList()
function with HTMLEvent as a parameter.
To fix your code, simply change the remove button from:
<button className="btn btn-danger" onChange={props.RemoveList(index)} >Remove</button>
to
<button className="btn btn-danger" onClick={() => props.RemoveList(index)}>Remove</button>
.
As a note, using index as a key to remove things from a list is a bad idea. Consider generating unique ID for each todo, and use that to identify the correct todo.
CodePudding user response:
You are calling the method directly, not passing a reference to it. also there isnt onChange
for button
So
onChange={props.RemoveList(index)}
should be changed to
onClick={() => props.RemoveList(index)}
Also regarding the second waring, add a key attribute to your li
tag
<li
className={
element.completed
? "list-group-item yes-comp"
: "list-group-item no-comp"
}
key={element.text}
>
Indexes are not best practice to be used as key
values, so i added the text
property here, but you should use something more "unique", which also should be used at your RemoveList
function.