每秒更新一次 React 组件

IT技术 javascript reactjs
2021-03-09 23:01:48

我一直在玩 React 并且有以下时间组件只呈现Date.now()到屏幕上:

import React, { Component } from 'react';

class TimeComponent extends Component {
  constructor(props){
    super(props);
    this.state = { time: Date.now() };
  }
  render(){
    return(
      <div> { this.state.time } </div>
    );
  }
  componentDidMount() {
    console.log("TimeComponent Mounted...")
  }
}

export default TimeComponent;

让这个组件每秒更新一次以从 React 的角度重新绘制时间的最佳方法是什么?

6个回答

您需要使用setInterval来触发更改,但您还需要在组件卸载时清除计时器以防止其留下错误和内存泄漏:

componentDidMount() {
  this.interval = setInterval(() => this.setState({ time: Date.now() }), 1000);
}
componentWillUnmount() {
  clearInterval(this.interval);
}
如果你想要一个封装这种东西的库,我做了 react-interval-rerender
2021-04-26 23:01:48
我在构造函数中添加了 setInterval 方法,效果更好。
2021-05-05 23:01:48

以下代码是来自 React.js 网站的修改示例。

原始代码可在此处获得:https : //reactjs.org/#a-simple-component

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      seconds: parseInt(props.startTimeInSeconds, 10) || 0
    };
  }

  tick() {
    this.setState(state => ({
      seconds: state.seconds + 1
    }));
  }

  componentDidMount() {
    this.interval = setInterval(() => this.tick(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  formatTime(secs) {
    let hours   = Math.floor(secs / 3600);
    let minutes = Math.floor(secs / 60) % 60;
    let seconds = secs % 60;
    return [hours, minutes, seconds]
        .map(v => ('' + v).padStart(2, '0'))
        .filter((v,i) => v !== '00' || i > 0)
        .join(':');
  }

  render() {
    return (
      <div>
        Timer: {this.formatTime(this.state.seconds)}
      </div>
    );
  }
}

ReactDOM.render(
  <Timer startTimeInSeconds="300" />,
  document.getElementById('timer-example')
);
使用 ES6,我需要更改一行,如 this.interval = setInterval(this.tick.bind(this),1000);
2021-04-23 23:01:48
我添加了一个格式化方法和一个“构造函数”属性以提高健壮性。
2021-04-23 23:01:48
使用这种方法时,我出于某种原因得到 this.updater.enqueueSetState 不是函数错误。setInterval 回调正确绑定到组件 this。
2021-04-25 23:01:48
您可以将链接添加到引用的 url 吗?谢谢~
2021-04-30 23:01:48
对于像我这样的白痴:不要命名计时器,updater因为它会破坏更新周期
2021-05-13 23:01:48

@Waisky 建议:

您需要使用setInterval来触发更改,但您还需要在组件卸载时清除计时器以防止其留下错误和内存泄漏:

如果你想做同样的事情,使用 Hooks:

const [time, setTime] = useState(Date.now());

useEffect(() => {
  const interval = setInterval(() => setTime(Date.now()), 1000);
  return () => {
    clearInterval(interval);
  };
}, []);

关于评论:

你不需要在里面传递任何东西[]如果传入time括号,则表示每次time更改值时都运行效果,即setInterval每次time更改时都会调用一个新的,这不是我们要找的。我们只想setInterval在组件挂载时调用一次,然后每 1000 秒setInterval调用setTime(Date.now())一次。最后,我们clearInterval在组件卸载时调用

请注意time,每次time更改值时,组件都会根据您在其中使用的方式进行更新这已无关把time[]useEffect

我注意到的不同之处在于,如果您在数组中传入 [time],它将在每个时间间隔创建和销毁组件。如果传递空数组[],它会不断刷新组件,只有在离开页面时才卸载它。但是,无论哪种情况,为了让它工作,我都必须添加 key={time} 或 key={Date.now()} 才能让它真正重新渲染。
2021-04-19 23:01:48
关于 effect 钩子React 文档告诉我们:“如果你想运行一个 effect 并且只清理一次(在挂载和卸载时),你可以传递一个空数组 ([]) 作为第二个参数。” 但 OP 希望效果每秒运行一次,即重复发生,即不仅仅是一次。
2021-04-27 23:01:48
为什么将空数组 ( []) 作为第二个参数传递给useEffect
2021-05-11 23:01:48

在组件的componentDidMount生命周期方法中,您可以设置一个间隔来调用更新状态的函数。

 componentDidMount() {
      setInterval(() => this.setState({ time: Date.now()}), 1000)
 }
正确,但正如最佳答案所暗示的那样,请记住清除时间以避免内存泄漏: componentWillUnmount() { clearInterval(this.interval); }
2021-05-13 23:01:48
class ShowDateTime extends React.Component {
   constructor() {
      super();
      this.state = {
        curTime : null
      }
    }
    componentDidMount() {
      setInterval( () => {
        this.setState({
          curTime : new Date().toLocaleString()
        })
      },1000)
    }
   render() {
        return(
          <div>
            <h2>{this.state.curTime}</h2>
          </div>
        );
      }
    }