简体   繁体   中英

How to prevent React from re render?

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>
    );
  }
}

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.

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:

  1. extra comparison with prevProps or prevState inside componentDidUpdate for class component:

    componentDidUpdate(prevProps, prevState) { if(prevState.taskList !== this.state.taskList) { // do your magic here } }

  2. 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 .

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>
...

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM