Search code examples
javascriptreactjsstatesetstate

react render is using old and new state values, instead of just the new value


I am trying to create a clock, where the user can select a location and the current time there is rendered on the screen. The code works fine for the first user button click. However, if they then select a different location, the hour state value should update to the new value. It does this, but react is rendering the old value to the screen too. The hour on the clock, therefore, flickers between the two different values. Can anyone explain why this is happening, and how I can only display the new hour value after the user clicks for a second time?

import React from 'react';
import ReactDOM from 'react-dom';
import ButtonClick from './Components/UserInputs.js'

 //define global time difference matrix
 var timeDiffMat= [0, 6, 1, 2, -5];

class Clock extends React.Component {

    constructor(props) {

        super(props);
        //this.userInput = this.userInput.bind(this);
        this.adjustForLocation = this.adjustForLocation.bind(this);
        this.tick = this.tick.bind(this);
        this.state = {CityfromChild: "", hours:0, minutes: 0, seconds: 0, 
test:''};
        //this.initialSetTime = this.initialSetTime.bind(this);
        this.setTime = this.setTime.bind(this);

    }


     adjustForLocation(citySelected, numberOfClicks) { 

        function getTimeDiff () {

            if (citySelected == "Local Time") return  timeDiffMat[0]

            if (citySelected =="Tokyo") return  timeDiffMat[1]

            if (citySelected =="Cape Town") return  timeDiffMat[2]

            if (citySelected =="Moscow")return  timeDiffMat[3]

            if (citySelected =="New York") return  timeDiffMat[4]

        }

        this.timeDiff = getTimeDiff(citySelected)

        this.tick(this.timeDiff)

    }


tick(timeDiff){

        setInterval(()=> this.setTime(timeDiff), 1000)

    }

    setTime(timeDiff){
        this.setState({
             seconds: new Date().getSeconds(), 
             minutes: new Date().getMinutes()
            });
        this.setState({hours: timeDiff + new Date().getHours() })
    }


    // unmount Clock Component and invalidate timer
     componentWillUnmount() {
            clearInterval(this.interval);
          }


    render() {
        return (
            <div className="border"> 
                <h3> Choose a city {}</h3>
                    <div className="button-container">
                        <ul>

                            <li> <ButtonClick getTimeOnClick = 
{this.userInput} adjustHoursForCity = {this.adjustForLocation} 
buttonLabel= "Local Time"/> </li> 
                            <li> <ButtonClick getTimeOnClick = 
{this.userInput} adjustHoursForCity = {this.adjustForLocation} 
buttonLabel= "Cape Town"/> </li>
                            <li> <ButtonClick getTimeOnClick = 
{this.userInput} adjustHoursForCity = {this.adjustForLocation} 
buttonLabel= "Moscow"/> </li>
                            <li> <ButtonClick getTimeOnClick = 
{this.userInput} adjustHoursForCity = {this.adjustForLocation} 
buttonLabel= "New York"/> </li>
                            <li> <ButtonClick getTimeOnClick = 
{this.userInput} adjustHoursForCity = {this.adjustForLocation} 
buttonLabel= "Tokyo"/> </li>
                            <button>{this.state.CityfromChild}</button>
                            <button>{this.state.test}</button>
                        </ul>   
                    </div>
                    <div>{this.state.hours}:{this.state.minutes}: 
{this.state.seconds} </div> 

            </div> 

        );
    }
}

Solution

  • When you update the time you create a new setInterval, but you don't clear the old one. So you will have multiple setInterval each setting the time using a different timeDiff.

    Try something like:

    tick(timeDiff) {
        if (this.timer) {
            clearInterval(this.timer);
        }
        this.timer = setInterval(() => this.setTime(timeDiff), 1000)
    }