我正在尝试做一个时钟组件,只是在网页中以本地格式提供日期和时间。我在我的webpack环境中使用命令行npm i -save导入了MomentJS。接下来我在我的Clock.jsx组件中写了这个(主要基于网站上的React示例)。
import React from 'react';
import Moment from 'moment';
export default class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {
dateTimestamp : Date.now()
};
}
tick = () => {
this.setState({dateTimestamp: this.state.dateTimestamp + 1});
console.log('tick');
}
componentDidMount() {
this.interval = setInterval(this.tick, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
const date = this.state.dateTimestamp;
return(
<div className="clock"> Heure locale : {date}</div>
);
}
}
这样做时间戳正确递增。但是,在对象中传递新的state元素时,第一个值(基于Date.now())是在构造函数中计算的,但是对于每个tick,只有时间戳递增格式化的日期会粘在其第一个值上。这是代码。
import React from 'react';
import Moment from 'moment';
export default class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {
dateTimestamp : Date.now(),
dateFormatted : Moment(Date.now()).toString()
};
}
tick = () => {
this.setState({dateTimestamp: this.state.dateTimestamp + 1});
console.log(this.state.dateTimestamp);
this.setState({dateFormatted: Moment(this.state.dateTimestamp).toString()});
console.log(this.state.dateFormatted);
}
...
render() {
const date = this.state.dateFormatted;
return(
<div className="clock"> Heure locale : {date}</div>
);
}
}
有没有人可以解释帮助我解决这个问题但最重要的是告诉我我的代码出了什么问题?
谢谢
更新:最后我对时刻的使用是不恰当的,即使我无法弄清楚为什么它不会以这种方式工作。在下面找到我正确的实现,以便每隔几秒刷新一次日期和时间。
import React from 'react';
import Moment from 'moment';
export default class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {
dateFormatted : Moment().locale('fr').format('dddd Do MMMM YYYY HH:mm:ss').toString()
};
}
tick = () => {
this.setState({
dateFormatted : Moment().locale('fr').format('dddd Do MMMM YYYY HH:mm:ss').toString()
});
}
componentDidMount() {
this.interval = setInterval(this.tick, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
const date = this.state.dateFormatted;
return(
<div className="clock"> Date (locale) : {date}</div>
);
}
}
这也“解决”下面公开的反模式问题(不同的交叉相关的setState()调用)。我会因任何其他原因需要时间戳,但我会找到解决方法。
答案 0 :(得分:7)
@KrzysztofSztompka是正确的,但我想补充说,维护两个单独的状态变量来表示当前日期作为数字和格式化字符串是反模式。派生状态变量(即可以使用另一个状态变量计算的状态变量)增加了开发人员的责任,使其始终保持两个状态变量同步。在这个简单的例子中,这似乎并不太难,但在更大,更复杂的组件/应用程序中,它可能会变得更加困难。相反,通常认为更好的做法是保持一个事实来源并在需要时动态计算任何派生值。以下是我将此模式应用于您的示例的方法。
import React from 'react';
import Moment from 'moment';
export default class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {
dateTimestamp : Date.now()
};
this.tick = this.tick.bind(this);
}
tick() {
this.setState({
dateTimestamp: this.state.dateTimestamp + 1
});
}
componentDidMount() {
this.interval = setInterval(this.tick, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
// Calculate the formatted date on the fly
const date = Moment(this.state.dateTimestamp).toString();
return(
<div className="clock"> Heure locale : {date}</div>
);
}
}
答案 1 :(得分:3)
将您的tick功能更改为:
tick = () => {
var timestamp = this.state.dateTimestamp + 1;
this.setState({
dateTimestamp: timestamp,
dateFormatted: Moment(timestamp).toString()
});
}
这是因为来自docs:
setState()不会立即改变this.state但会创建一个 待定状态转换。调用后访问this.state 方法可以返回现有值。
因此,在您的下一个setState调用中,它使用旧值。我的命题立即改变了这两个值。