在react组件中在哪里应用我的 moment() 函数?

IT技术 javascript reactjs momentjs react-jsx
2021-05-24 13:31:49

我正在尝试做一个时钟组件,只是为了在网页中以本地格式提供日期和时间。我使用命令行 npm i moment --save 在我的 webpack 环境中导入了 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>
    );
}

}

这样做时间戳正确增加。然而,当在对象中传递一个新的状态元素时,第一个值(基于 Date.now() )在构造函数中计算,但对于每个刻度,只有时间戳在增加,格式化的日期卡在它的第一个值上。这是代码。

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>
    );
}

}

有没有人可以解释帮助我解决这个问题,但最重要的是告诉我我的一段代码出了什么问题?

谢谢

更新:最后,我对 moment 的使用并不合适,即使我不知道为什么它不会以这种方式工作。在下面找到我的正确实现,以每秒钟刷新一次日期和时间。

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() 调用)。由于任何其他原因,我需要时间戳,但我会找到解决方法。

2个回答

@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>
    );
  }

}

将您的滴答函数更改为:

tick = () => {
  var timestamp = this.state.dateTimestamp + 1;
  this.setState({
    dateTimestamp: timestamp,
    dateFormatted: Moment(timestamp).toString()
  });
}

这是因为从文档

setState() 不会立即改变 this.state 而是创建一个挂起的状态转换。调用此方法后访问 this.state 可能会返回现有值。

因此在您的下一个 setState 调用中使用旧值。我的提议一下子改变了这两个值。