Reputation: 41
I'm learning React and am currently trying to create a todo list. Everything works fine, however, when I try to delete an item in the array, the whole page gets re-rendered.
Can someone please let me know where I went wrong? I just want to delete a specific item once the button is clicked and not re-render the whole page.
Code:
import React, { Component } from "react";
import "./todo.css";
class Todo extends Component {
constructor(props) {
super(props);
this.state = {
task: "",
taskList: []
};
}
handleAdd = e => {
e.preventDefault();
this.setState({
task: "",
taskList: [...this.state.taskList, this.state.task]
});
};
onChange = e => {
this.setState({
task: e.target.value
});
};
handleDelete = task => {
console.log(task);
const newtaskList = this.state.taskList.splice(task, 1);
this.setState({
taskList: newtaskList
});
console.log(task);
};
render() {
return (
<form className='App'>
<div className='input input-group mb-3'>
<input
type='text'
className='form-control'
placeholder='Enter a task'
value={this.state.task}
onChange={this.onChange}
/>
<button className='btn btn-primary' onClick={this.handleAdd}>
ADD
</button>
</div>
<div className='output' id='output'>
<ul className='list-group'>
{this.state.taskList.map((task, index) => (
<li
className='list-group-item'
key={index}
style={{
display: "flex",
justifyContent: "space-between",
alignContent: "center"
}}>
{task}
<div className='input-group-prepend'>
<button
className='btn btn-danger'
onClick={() => this.handleDelete(task)}>
Done
</button>
</div>
</li>
))}
</ul>
</div>
</form>
);
}
}
Upvotes: 4
Views: 5642
Reputation: 336
1.You are using form
element of html. And since you are using button inside it you need to add e.preventDefault
else it would act like submit and refresh the page.
2.While passing params in handleDelete
you are not passing event
neither you are passing index
. To use splice
you need the index
of the element.
3.In react, I would suggest to use spread operator
that helps not to mutate the state.
So, please replace these two things.
handleDelete = (e , index) => {
e.preventDefault();
const { taskList } = this.state;
this.setState({
taskList: [...taskList.slice(0 , index) , ...taskList.slice(index + 1)]
});
};
and, while calling handle delete function use,
onClick={(e) => this.handleDelete(e, index)}
And, regarding re-render. React will always re-render the component if any state in that component is getting changed. Here, tasklist state is getting changed when you are deleting. So component is getting re-rendered.
Upvotes: 0
Reputation: 1995
If you want to avoid refreshing page when submit event occure then you should use preventDefault()
.
If you want to disable whole page rendering in React
and re-render only some parts of you page, you can use two solutions:
extra comparison with prevProps
or prevState
inside componentDidUpdate
for class component:
componentDidUpdate(prevProps, prevState) {
if(prevState.taskList !== this.state.taskList) {
// do your magic here
}
}
useEffect()
hook in functional component:
You can tell React to skip applying an effect if certain values haven’t changed between re-renders. To do so, pass an array as an optional second argument to useEffect:
useEffect(() => {
// do your magic here
}, [taskList]); // Only re-run the effect if taskList changes
More information about this kind of feature you can find in official React documentation.
Upvotes: 1
Reputation: 6418
Splice removes an element by index and returns the removed element and it manipulates the original array after splicing.
What you need to do is to change the handleDelete
function. First parameter of an event function is the event object. So pass it as the first parameter and bind any other params with it.
You can try this-
handleDelete = (e, index) => {
console.log(index);
e.preventDefault();
const copyTask = [...this.state.taskList];
copyTask.splice(index, 1); // Splice directly change the copyTask array.
this.setState({
taskList: copyTask
});
};
And also change this line-
onClick={(e) => this.handleDelete(e, index)}
First param is the event
object. Then pass the index other than the item.
Upvotes: 0
Reputation: 11622
This is caused by form submit in your react component as mentioned in the comments, you should use e.preventDefault() to prevent the default behavior for the button submit:
...
<button
className='btn btn-danger'
onClick={(e) => {
e.preventDefault();
this.handleDelete(task)
}}>
Done
</button>
...
Upvotes: 0
Reputation: 74738
As you can see in the comment you have a form in your template. If you click the button your form in the template get submitted which causes in a postback which is a page reload. So either you stop the submission of form(1) or change the type of the button to type="button"
:
<button type="button"
The default behavior is type="submit"
, so changing the type would resolve your issue.
1. You don't have any form submit event.
Upvotes: 1