我正在为我的气象应用程序开发组件,其功能之一是在Farenheit和celcius之间切换。该组件从名为current
,low
,high
和tempScale
的父组件中获取4个属性。 tempScale
属性用作从父组件中获取true
或false
值的布尔值。 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}°</h3>
<h3>{this.state.lowTemperature}°</h3>
<h3>{this.state.highTemperature}°</h3>
<button onClick={this.toggleTemperatureScale}>click</button>
</article>
);
}
}
任何人都可以发现这种行为的发生方式和原因吗?
答案 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 了解如果您认为需要某种状态来依赖该怎么办 在道具上。