Home > Back-end >  React setState is not re-rendering current values,instead rendering the previous stored value
React setState is not re-rendering current values,instead rendering the previous stored value

Time:11-07

I have tried to re-render my class component with user values , but set state is only rendering the previous value, and then the current value. By which I mean, it is working one step back. Lets say initial value was set to 0. After onclick, i wanted to update the value to 20,but it gave me 0. Now when I try to update to 40, it gives me the value 20. Can someone please help me with the solution and detailed explanation as to why is this happening. My Class Component

import React, { Component } from 'react'

export default class TemperatureRange extends Component {
    constructor(){
        super()
        this.state={
            initialTemperature:0
        }
    }
    
    handleClick(userValue){
        
        this.setState({
            initialTemperature:userValue
        })
        if(this.state.initialTemperature>0 && this.state.initialTemperature<30){
            document.querySelector("#container").style.backgroundColor="red";
        }
        else{
            document.querySelector("#container").style.backgroundColor="green";
        }
    }
    render() {
        return (
            <div id="container">
                <input type="number" id="number" />
                <input type="button" id="button" value="Check" onClick={()=>{this.handleClick(document.querySelector("#number").value)}}/>
            </div>
        )
    }
}

App.js

import logo from './logo.svg';
import './App.css';
import TemperatureRange from './Components/TemperatureRange'

function App() {
  return (
    <div className="App">
      <TemperatureRange/>
    </div>
  );
}

export default App;

I am confused as to why my state is not updated on click with the present user value. Please help me in this.

CodePudding user response:

When you call the setState function the state isn't changed immediately as setState is asynchronous. I suggest moving your effect in the componentDidUpdate (plus componentDidMount) lifecycle method:

import React, { Component } from 'react'

export default class TemperatureRange extends Component {
    constructor(){
        super()
        this.state={
            initialTemperature:0
        }
    }
    
    handleClick(userValue){
        this.setState({
            initialTemperature:userValue
        })
    }

    componentDidMount(){
        if(this.state.initialTemperature>0 && this.state.initialTemperature<30){
            document.querySelector("#container").style.backgroundColor="red";
        }
        else{
            document.querySelector("#container").style.backgroundColor="green";
        }
    }

    componentDidUpdate(){
        if(this.state.initialTemperature>0 && this.state.initialTemperature<30){
            document.querySelector("#container").style.backgroundColor="red";
        }
        else{
            document.querySelector("#container").style.backgroundColor="green";
        }
    }

    render() {
        return (
            <div id="container">
                <input type="number" id="number" />
                <input type="button" id="button" value="Check" onClick={()=>{this.handleClick(document.querySelector("#number").value)}}/>
            </div>
        )
    }
}

CodePudding user response:

Like @happydev already stated, the setState method will not change the value immediately, react will first re-render the page, and the value will then be updated.

However, if you are keeping to the class based Components, I would suggest the following solution instead:

import React, { Component } from 'react'

export default class TemperatureRange extends Component {
    constructor(){
        super()
        this.state = {
            initialTemperature: 0,
            backgroundColor: "red",
        }
    }
    
    handleClick(userValue) {
        const color = userValue > 0 && userValue < 30 ? 'red' : 'green';
        this.setState({
            initialTemperature: userValue,
            backgroundColor: color,
        })
    }
    render() {
        const { backgroundColor } = this.state;
        return (
            <div id="container" style={{ backgroundColor }}>
                <input type="number" id="number" />
                <input 
                  type="button" id="button" value="Check" 
                  onClick={() => {
                   this.handleClick(document.querySelector("#number").value)}
                  }
                 />
            </div>
        )
    }
}

This way, your code looks cleaner, I you don't need to access direct HTML DOM elements. You can go the extra step and create a state for the number input, and use the onChange method, but this would out of scope of your question.

In general, document.querySelector in most cases, not the "react" way of doing things, I will not go into too much detail here, there are cases where I would maybe get direct HTML elements with document.querySelector, but I would 99.9999999% of the time avoid using direct DOM elements, as it contradicts the concepts of react.

  • Related