反应:第一次尝试更新组件状态失败

时间:2018-10-15 03:58:40

标签: reactjs ecmascript-6

我正在为我的气象应用程序开发组件,其功能之一是在Farenheit和celcius之间切换。该组件从名为currentlowhightempScale的父组件中获取4个属性。 tempScale属性用作从父组件中获取truefalse值的布尔值。 true表示温度应以华氏度显示,false表示应为摄氏度。

我将tempScale属性直接加载到组件状态为temperatureScale的属性中,并具有一个名为setTemperature的函数,该函数在componentDidMount方法中运行,该函数设置另一个根据其值确定属性。我创建了一个名为toggleTemperatureScale的函数,该函数可切换temperatureScale属性并运行setTemperature函数。

一切正常,但是当单击按钮在华氏度和摄氏度之间切换时,第一次尝试将不起作用。当console.log()进入状态时,我感到更加困惑,这就是正在发生的事情。

/*Value when component loads.  42, 50 and 35 are rendered on my screen.*/
{temperatureScale: true, currentTemperature: 0, lowTemperature: 0, highTemperature: 0}

/*Value after first click, values still the same on the screen*/
{temperatureScale: true, currentTemperature: 42, lowTemperature: 50, highTemperature: 35}

/*Value after second click, values rendered on screen are 6, 10 and 2*/
{temperatureScale: false, currentTemperature: 42, lowTemperature: 50, highTemperature: 35}

/*Value after third click, values rendered to screen are back to 42, 50 and 35*/
{temperatureScale: true, currentTemperature: 6, lowTemperature: 10, highTemperature: 2}

似乎是由于某种原因导致某种不同步,这是第一次单击无法正常工作的原因,这是我的组件。

export class TemperatureDisplayComponent extends Component{
    constructor(props){
        super(props);
        this.state = {
            temperatureScale   : props.tempScale,
            currentTemperature : 0,
            lowTemperature     : 0,
            highTemperature    : 0
        };
        this.setTemperature         = this.setTemperature.bind(this);
        this.toggleTemperatureScale = this.toggleTemperatureScale.bind(this);
    }

    setTemperature(){
        const currentTemp = (this.state.temperatureScale === true) ? eliminateDecimals(calculateFarenheitTemperature(eliminateDecimals(this.props.current))) : eliminateDecimals(this.props.current),
              hiTemp      = (this.state.temperatureScale === true) ? eliminateDecimals(calculateFarenheitTemperature(eliminateDecimals(this.props.low))) : eliminateDecimals(this.props.low),
              lowTemp     = (this.state.temperatureScale === true) ? eliminateDecimals(calculateFarenheitTemperature(eliminateDecimals(this.props.high))) : eliminateDecimals(this.props.high);

        this.setState({ currentTemperature : currentTemp, lowTemperature : lowTemp, highTemperature : hiTemp });
        console.log(this.state);
    }

    toggleTemperatureScale(){
        this.setState(prevState =>({ temperatureScale : !prevState.temperatureScale }));
        this.setTemperature();
        //console.log(this.state);
    }

    componentDidMount(){
        this.setTemperature();
        console.log(this.state);
    }

    componentDidUpdate(){
        //console.log(this.state);
    }

    render(){
        return(
            <article>
                <h3>{this.state.currentTemperature}&deg;</h3>
                <h3>{this.state.lowTemperature}&deg;</h3>
                <h3>{this.state.highTemperature}&deg;</h3>
                <button onClick={this.toggleTemperatureScale}>click</button>
            </article>
        );
    }
}

任何人都可以发现这种行为的发生方式和原因吗?

1 个答案:

答案 0 :(得分:1)

因为setState()并不总是立即更新组件。如果您想在应用更新后立即看到结果,则应使用setState回调(setState(updater, callback),如下所示:

 setTemperature(){
        const currentTemp = (this.state.temperatureScale === true) ? eliminateDecimals(calculateFarenheitTemperature(eliminateDecimals(this.props.current))) : eliminateDecimals(this.props.current),
              hiTemp      = (this.state.temperatureScale === true) ? eliminateDecimals(calculateFarenheitTemperature(eliminateDecimals(this.props.low))) : eliminateDecimals(this.props.low),
              lowTemp     = (this.state.temperatureScale === true) ? eliminateDecimals(calculateFarenheitTemperature(eliminateDecimals(this.props.high))) : eliminateDecimals(this.props.high);

        this.setState(
            { 
              currentTemperature : currentTemp, 
              lowTemperature : lowTemp, 
              highTemperature : hiTemp 
            },
            () => {
              console.log(this.state);
            }
        );           
    }

您应该避免像以前那样将道具复制到状态中

   this.state = {
        temperatureScale   : props.tempScale,   //Don't do this
        ...
   };

以供参考:https://reactjs.org/docs/react-component.html#constructor

  

注意

     

避免将道具复制到状态中!这是一个常见的错误:

constructor(props) {
 super(props);
 // Don't do this!
 this.state = { color: props.color };
}
     

问题在于,两者都是不必要的(您可以使用   而是直接使用this.props.color,并创建错误(对   color道具不会反映在状态中。

     

仅在您有意忽略道具的情况下使用此模式   更新。在这种情况下,重命名要调用的道具是有意义的   initialColor或defaultColor。然后,您可以强制组件   通过changing its key“重置”其内部状态   必要时。

     

阅读我们的blog post on avoiding derived state   了解如果您认为需要某种状态来依赖该怎么办   在道具上。