每秒更新React组件

时间:2016-09-10 12:28:06

标签: javascript reactjs

我一直在使用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的角度来看,让这个组件每秒更新以重新绘制时间的最佳方法是什么?

8 个答案:

答案 0 :(得分:76)

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

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

答案 1 :(得分:75)

这是React.js网站的一个例子:

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

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

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

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

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

 ReactDOM.render(<Timer />, mountNode);

答案 2 :(得分:20)

@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,然后setInterval每1000秒调用一次setTime(Date.now())。最后,在卸载组件时,我们调用clearInterval

请注意,每次time的值更改时,组件都会根据您在其中使用time的方式进行更新。这与将time放在[]的{​​{1}}中无关。

答案 3 :(得分:6)

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

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

答案 4 :(得分:3)

我自己更喜欢setTimeout而不是setInterval,但是在基于类的组件中没有找到解决方案。你可以在基于类的组件中使用这样的东西:

基于类的组件和 setInterval:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      date: new Date()
    };
  }

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

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

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      this.state.date.toLocaleTimeString()
    );
  }
}

ReactDOM.render( 
  <Clock / > ,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app" />

基于函数的组件和 setInterval:

https://codesandbox.io/s/sweet-diffie-wsu1t?file=/src/index.js

基于函数的组件和 setTimeout:

https://codesandbox.io/s/youthful-lovelace-xw46p

答案 5 :(得分:2)

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

答案 6 :(得分:0)

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

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

此外,您可以使用Date.now()并与我上面提供的componentDidMount()实现一起使用,但是您将获得大量令人讨厌的数字更新,这是人类无法理解的,但是从技术上讲,这是时候自1970年1月1日以来,以毫秒为单位进行更新,但是我们希望使这一时间对人类阅读时间的方式具有可读性,因此除了学习和实现setInterval之外,您还想了解new Date()和{ {1}},您将像这样实现它:

toLocaleTimeString()

注意,我还删除了class TimeComponent extends Component { state = { time: new Date().toLocaleTimeString() }; } componentDidMount() { setInterval(() => { this.setState({ time: new Date().toLocaleTimeString() }) }, 1000) } 函数,您不一定需要它,我的重构相当于100%等效于使用constructor()函数初始化站点。

答案 7 :(得分:0)

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

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