user10900191
user10900191

Reputation:

ReactJs : How to prevent componentWillUpdate from re-rendering multiple times

I am creating a simple Todo App, I am using componentDidMount to display the data from the database. But the problem is, Once I add a new data the data gets stored but it doesn't display on to the page unless I refresh it.

Then I came across componentDidUpdate. It works perfectly, But it re-renders multiple times, What I mean is it keeps requesting the server to check for new data. I am using Express for backend

So could anyone tell me how to prevent this ? or if there is any better solution?

Here is the current code:

  class Navbar extends Component {
  state = {
    userArray: [],
    username: "",
    email: ""
  };

  //Storing the Data

  addBtn = e => {
    e.preventDefault();

    var data = {
      username: this.state.username,
      email: this.state.email
    };

    fetch("/user", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data)
    })
      .then(response => {
        if (response.status >= 400) {
          throw new Error("Bad response from server");
        }
        return response.json();
      })
      .then(data => {
        console.log(data);
        if (data === "success") {
          console.log("Yay");
        }
      })
      .catch(err => {
        console.log(err);
      });
    console.log(this.state.userArray);
  };


  componentDidMount() {
    this.displayData();
  }

  componentWillUpdate() {
    this.displayData();
  }

//Displaying the Data

  displayData() {
    fetch("/user")
      .then(data => data.json())
      .then(data => {
        this.setState({
          userArray: data
        });
      });
  }

  //Handling the input values

  logChange = e => {
    this.setState({
      [e.target.name]: e.target.value
    });
  };

Upvotes: 0

Views: 747

Answers (4)

Thanveer Shah
Thanveer Shah

Reputation: 3323

Everyone gave the right answer , But there is a tiny mistake.

You should call the displayData() outside of the if condition

.then(data => {
  console.log(data);
  if (data === "success") {
    console.log("Yay");
  }
   this.displayData();
})

Upvotes: 0

cross19xx
cross19xx

Reputation: 3487

So, let's try and understand why there was a lot of calls to the server.

When componentDidMount is created, you called displayData, which then setState. As soon as setstate is called, it calls componentDidUpdate which calls displayData again, which then calls setState. And the loop goes on (probably till you run out of memory).

You could try this class:

import React from 'react';

export default class Navbar extends React.Component {
    state = {
        userArray: [],
        username: '',
        email: ''
    };

    componentDidMount() {
        this.displayData();
    }

    addBtn = e => {
        e.preventDefault();

        var data = {
            username: this.state.username,
            email: this.state.email
        };

        fetch('/user', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(data)
        })
            .then(response => {
                if (response.status >= 400) {
                    throw new Error('Bad response from server');
                }
                return response.json();
            })
            .then(data => {
                console.log(data);
                if (data === 'success') {
                    this.displayData();
                }
            })
            .catch(err => {
                console.log(err);
            });
    };

    displayData() {
        fetch('/user')
            .then(data => data.json())
            .then(data => {
                this.setState({
                    userArray: data
                });
            });
    }
}

Basically, what I did was I removed the call to displayData in componentDidUpdate and then called the displayData when the ApI call was successful

Upvotes: 1

namth
namth

Reputation: 3117

componentDidMount is the right place to load the first time, and then, after creating new Todo, you need to refresh the list right after POST request complete

.then(data => {
  console.log(data);
  if (data === "success") {
    console.log("Yay");
    this.displayData();
  }
})

To impove performace, you should return new Todo record after POST, so you only push it to the list userArray in state, no need to fetch whole list again

Upvotes: 1

Ashish
Ashish

Reputation: 4330

For this, you need to first understand how componentDidMount and componentWillUpdate works in React. They are lifecycle methods of react.

componentDidMount gets called after the component is mounted. It gets called only once and never gets called again if not unmounted and mounted again.

componentWillUpdate gets called every time state changes and re-rendering is going to happen.

As commented by @trixn: You need to call this.setState() in addBtn when you have the data instead of repeatedly calling this.displayData()

Upvotes: 0

Related Questions