【问题标题】:react render is using old and new state values, instead of just the new value反应渲染正在使用新旧状态值,而不仅仅是新值
【发布时间】:2019-11-25 01:40:40
【问题描述】:

我正在尝试创建一个时钟,用户可以在其中选择一个位置并在屏幕上呈现当前时间。该代码适用于第一个用户按钮单击。但是,如果他们随后选择了不同的位置,则小时状态值应更新为新值。它这样做了,但是 react 也将旧值渲染到屏幕上。因此,时钟上的小时在两个不同的值之间闪烁。谁能解释为什么会发生这种情况,以及我如何只能在用户第二次点击后显示新的小时值?

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> 

        );
    }
}

【问题讨论】:

  • 为什么你连续两次调用 setState 而不包括第一个 setState 中的小时数?也许这已经可以解决您的问题
  • 我也试过这个,但我仍然遇到同样的问题
  • 嗯,好吧,但你还是不要那样做,我再看看

标签: javascript reactjs state setstate


【解决方案1】:

当您更新时间时,您会创建一个新的setInterval,但不会清除旧的。因此,您将有多个setInterval,每个设置时间使用不同的timeDiff

尝试类似:

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

【讨论】:

  • 所以你是说它同时运行setInterval 的两个实例?
  • 是的,tick函数会新建一个,所以每次点击按钮设置timeDiff都会创建一个
  • @SeanBarker 我添加了一些可以解决问题的代码。
【解决方案2】:

您应该将setTimeInterval 绑定到您的组件,例如this.mySetTimeInterval = setTimeInterval(() =&gt; {}); 在其他任何地方你都可以停止运行间隔:

clearInterval(this.mySetTimeInterval)

【讨论】:

  • 为什么我需要将区间绑定到它的组件?只是为了让我以后可以调用它来清除它吗?
  • 组件卸载时,间隔会一直在后台运行,导致内存泄漏。如果绑定到组件,可以在componentWillUnmount中清除
【解决方案3】:

您的代码中没有this.interval,就像componentWillUnmount 中使用的那样,在函数tick 中,我相信您想将setInterval 调用的结果存储在一个名为interval 的变量中。正如@rebecca 所说,您可能应该使用

 setTime(timeDiff) {
    setState(/* To avoid race conditions */ function(){
       return { 
       seconds: new Date().getSeconds(),
       minutes: new Date().getMinutes(),
       hours: timeDiff + new Date().getHours() 
     })
  }

tick(timeDiff) {
    this.interval = setInterval(() => this.setTime(timeDiff), 1000)
  }

为了避免竞争条件

【讨论】:

    猜你喜欢
    • 2021-10-15
    • 2021-05-18
    • 1970-01-01
    • 2020-10-19
    • 1970-01-01
    • 2022-11-12
    • 2020-01-13
    • 2021-01-27
    • 1970-01-01
    相关资源
    最近更新 更多