amoeboar
amoeboar

Reputation: 355

React JS - Live clock update

I've got a clock function that gets time and renders out the hours, minutes and seconds, and I'm trying to update the data on screen in real time, but for some reason my setInterval function isn't doing what I expect.

I thought react's render method is supposed to render data in real time. Do I need ajax for this? Can anyone offer some advice?

var CityRow = React.createClass({

  render: function() {

    var currentdate = new Date();

    function getTime() {
      // get local time based on the UTC offset
      this.hours = currentdate.getUTCHours() + parseInt(this.props.UTCOffset);    

      // correct for number over 24, and negatives
      if( this.hours >= 24 ){ this.hours = this.hours - 24; }
      if( this.hours < 0   ){ this.hours = this.hours + 12; }

      // add leading zero, first convert hours to string
      this.hours = this.hours + "";
      if( this.hours.length == 1 ){ this.hours = "0" + this.hours; }

      // minutes are the same on every time zone
      this.minutes = currentdate.getUTCMinutes();

      // add leading zero, first convert hours to string
      this.minutes = this.minutes + "";
      if( this.minutes.length == 1 ){ this.minutes = "0" + this.minutes; }

      this.seconds = currentdate.getUTCSeconds();
    }

    window.setInterval(function () {
      getTime();
    }, 1000);

    return(
      <div className="city-row" ref="cityRow">
        <span className="city-time">{this.hours}:{this.minutes}:{this.seconds}</span>
        </div>
      </div>
    )
  }
});

Upvotes: 8

Views: 32618

Answers (6)

patrik kings
patrik kings

Reputation: 467

functional component

function Time() {

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

  React.useEffect(() => {
    setInterval(() => {
     setTime(new Date());
    }, 1000);
  }, []);

 return <span>{time.toLocaleString("en-US", {

  dateStyle: "full",
  timeStyle: "medium",
    hour12: false,
  
})} </span>;
 }

Upvotes: 1

Azzam Jihad Ulhaq
Azzam Jihad Ulhaq

Reputation: 111

import React, { Component } from "react";

class Clock extends Component {
    constructor (props) {
        super(props);

        this.state = {
            dateClass: new Date()
        }

        this.time = this.state.dateClass.toLocaleTimeString();
        this.hourMin = this.time.length === 10? this.time.slice(0) : this.time.slice(0,5);
    }

    setTime = () => {
        this.setState({
            dateClass: new Date()
        })
        this.time = this.state.dateClass.toLocaleTimeString();
        this.hourMin = this.time.length === 10? this.time.slice(0) : this.time.slice(0,5);
    }

    componentDidMount () {
        setInterval(this.setTime, 1000)
    }
    
    render () {
        return (
            <div>
                {this.hourMin}
            </div>
        )
    }
}

export default Clock;

Hey, I have more simple approach.

Upvotes: 0

Aravindh
Aravindh

Reputation: 1

class Clock extends React.Component {
    
   state ={time:null}
    
    componentDidMount() {
        setInterval(() => {
            this.setState({time:new Date().toLocaleTimeString()})}, 1000)
       }

    render() {
            return (
            <div className="time">
                The time is: {this.state.time}
            </div>
             );
         }
  }

  ReactDOM.render( 
      <Clock />,
      document.getElementById('root') );

Upvotes: 0

Eliecer Chicott
Eliecer Chicott

Reputation: 581

Update of "TheSchecke" answer to show UTC date on format "YYYY-MM-DD HH:mm:ss":

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() {
    const ISOStringDate = this.state.date.toISOString();
    return (
        <div>
            <h1>UTC Time:</h1>
            <h2>{ISOStringDate.substring(0, 19).replace('T', ' ')}</h2>
        </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

Upvotes: 0

KevinH
KevinH

Reputation: 1144

The official React Docs describe exactly what you need (and even explains why you should do it as described):

--> React Docs: State and Lifecycle

Example on CodePen:

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 (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

Upvotes: 16

noveyak
noveyak

Reputation: 3300

There seems to be a couple problems with your code. First is the closing div in the render function which causes your element to not even render.

Next you might want to take a look at state/props and React general lifecycle methods to get a better idea of program flow. The setInterval should be put in componentDidMount so its not called every time your component renders and creates a lot of timers. It also might help to put hours, minutes, and seconds as state so that way when these change your component re-renders automatically.

I modified your code below and put an example on jsfiddle. It does not print the seconds properly (just like in your getTime method) but hopefully it will give you a better idea of how logic should flow.

https://jsfiddle.net/rpg6t4uc/

var CityRow = React.createClass({
  setTime: function(){

    var currentdate = new Date();
    var hours = currentdate.getUTCHours() + parseInt(this.props.UTCOffset);    

      // correct for number over 24, and negatives
      if( hours >= 24 ){ hours -= 24; }
      if( hours < 0   ){ hours += 12; }

      // add leading zero, first convert hours to string
      hours = hours + "";
      if( hours.length == 1 ){ hours = "0" + hours; }

      // minutes are the same on every time zone
      var minutes = currentdate.getUTCMinutes();

      // add leading zero, first convert hours to string
      minutes = minutes + "";
      if( minutes.length == 1 ){ minutes = "0" + minutes; }

      seconds = currentdate.getUTCSeconds();
      console.log(hours, minutes, seconds)
      this.setState({
        hours: hours,
        minutes: minutes,
        seconds: seconds
      });
  },
  componentWillMount: function(){
    this.setTime();
  },
  componentDidMount: function(){
     window.setInterval(function () {
      this.setTime();
    }.bind(this), 1000);
  },
  render: function() {

    return(
      <div className="city-row" ref="cityRow">
        <span className="city-time">{this.state.hours}:{this.state.minutes}:{this.state.seconds}</span>
      </div>
    )
  }
});

Upvotes: 13

Related Questions