Javascript 每秒更新 React 组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39426083/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 22:32:54  来源:igfitidea点击:

Update React component every second

javascriptreactjs

提问by snowflakekiller

I have been playing around with React and have the following time component that just renders Date.now()to the screen:

我一直在玩 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;

What would be the best way to get this component to update every second to re-draw the time from a React perspective?

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

回答by Waiski

You need to use setIntervalto trigger the change, but you also need to clear the timer when the component unmounts to prevent it leaving errors and leaking memory:

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

componentDidMount() {
  this.interval = setInterval(() => this.setState({ time: Date.now() }), 1000);
}
componentWillUnmount() {
  clearInterval(this.interval);
}

回答by snowflakekiller

The following code is a modified example from React.js website.

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

Original code is available here: https://reactjs.org/#a-simple-component

原始代码可在此处获得: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')
);

回答by 1man

@Waisky suggested:

@Waisky 建议:

You need to use setIntervalto trigger the change, but you also need to clear the timer when the component unmounts to prevent it leaving errors and leaking memory:

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

If you'd like to do the same thing, using Hooks:

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

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

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

Regarding the comments:

关于评论:

You don't need to pass anything inside []. If you pass timein the brackets, it means run the effect every time the value of timechanges, i.e., it invokes a new setIntervalevery time, timechanges, which is not what we're looking for. We want to only invoke setIntervalonce when the component gets mounted and then setIntervalcalls setTime(Date.now())every 1000 seconds. Finally, we invoke clearIntervalwhen the component is unmounted.

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

Note that the component gets updated, based on how you've used timein it, every time the value of timechanges. That has nothing to do with putting timein []of useEffect.

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

回答by erik-sn

In the component's componentDidMountlifecycle method, you can set an interval to call a function which updates the state.

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

 componentDidMount() {
      setInterval(() => this.setState({ time: Date.now()}), 1000)
 }

回答by Jagadeesh

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

回答by Daniel

So you were on the right track. Inside your componentDidMount()you could have finished the job by implementing setInterval()to trigger the change, but remember the way to update a components state is via setState(), so inside your componentDidMount()you could have done this:

所以你走在正确的轨道上。在您的内部,您componentDidMount()可以通过实现setInterval()触发更改来完成工作,但请记住更新组件状态的方法是 via setState(),因此在您的内部您componentDidMount()可以这样做:

componentDidMount() {
  setInterval(() => {
   this.setState({time: Date.now()})    
  }, 1000)
}

Also, you use Date.now()which works, with the componentDidMount()implementation I offered above, but you will get a long set of nasty numbers updating that is not human readable, but it is technically the time updating every second in milliseconds since January 1, 1970, but we want to make this time readable to how we humans read time, so in addition to learning and implementing setIntervalyou want to learn about new Date()and toLocaleTimeString()and you would implement it like so:

此外,您使用Date.now()which 与componentDidMount()我上面提供的实现一起工作,但是您将获得一长串令人讨厌的数字更新,这些数字不是人类可读的,但从技术上讲,这是自 1970 年 1 月 1 日以来每秒更新的时间,以毫秒为单位,但我们想使这次可读性我们人类如何读取时间,所以除了学习和实施setInterval要了解new Date()toLocaleTimeString()你会实现它,像这样:

class TimeComponent extends Component {
  state = { time: new Date().toLocaleTimeString() };
}

componentDidMount() {
  setInterval(() => {
   this.setState({ time: new Date().toLocaleTimeString() })    
  }, 1000)
}

Notice I also removed the constructor()function, you do not necessarily need it, my refactor is 100% equivalent to initializing site with the constructor()function.

请注意,我也删除了该constructor()函数,您不一定需要它,我的重构 100% 等效于使用该constructor()函数初始化站点。

回答by jarora

Owing to changes in React V16 where componentWillReceiveProps() has been deprecated, this is the methodology that I use for updating a component. Notice that the below example is in Typescript and uses the static getDerivedStateFromProps method to get the initial state and updated state whenever the Props are updated.

由于 React V16 中 componentWillReceiveProps() 已被弃用的更改,这是我用于更新组件的方法。请注意,以下示例在 Typescript 中,并使用静态 getDerivedStateFromProps 方法在更新 Props 时获取初始状态和更新状态。

    class SomeClass extends React.Component<Props, State> {
  static getDerivedStateFromProps(nextProps: Readonly<Props>): Partial<State> | null {
    return {
      time: nextProps.time
    };
  }

  timerInterval: any;

  componentDidMount() {
    this.timerInterval = setInterval(this.tick.bind(this), 1000);
  }

  tick() {
    this.setState({ time: this.props.time });
  }

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

  render() {
    return <div>{this.state.time}</div>;
  }
}