one-hand-octopus
one-hand-octopus

Reputation: 2743

How to render the ReactDOM every second?

I'm new to React, I'm trying to follow this ticking clock example but do something a bit different. I'd like the ReactDOM to be rendered in the index.js. Here is my code:

Timer.js:

import React from 'react';

const Timer = () => {
    const tick = () => {
        return new Date().toLocaleTimeString().toString();
    };

    const element = (
        <div>
            <h1>Hello World!</h1>
            <h2>It is {tick()} !</h2>
        </div>
    );

    return (
        element
    );
};

export default Timer;

App.js:

/*jshint esversion: 8 */
import React from 'react';
import logo from './logo.svg';
import './App.css';
import Timer from './Timer'

function App() {
  return (
    <div className="App">
      <Timer />
    </div>
  );
}

export default App;

index.js:

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import * as serviceWorker from "./serviceWorker";
import App from './App';

setInterval(ReactDOM.render(<App />, document.getElementById("root")), 1000);

serviceWorker.unregister();

But it only prints the current time on screen, not ticking. Why does the code setInterval(ReactDOM.render(<App />, document.getElementById("root")), 1000); not work on index.js?

Upvotes: 1

Views: 245

Answers (3)

Thiago
Thiago

Reputation: 303

It is a good practice to avoid calling directly the render function, you could make your Timer a Component and let it update with state changes, which is how react would do it with its life cycle. For example:

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      time: new Date().toLocaleTimeString().toString()
    };
  }
  tick() {
    this.setState({
      time: new Date().toLocaleTimeString().toString()
    });
  }
  componentDidMount() {
    this.intervalID = setInterval(
      () => this.tick(),
      1000
    );
  }
  componentWillUnmount() {
    clearInterval(this.intervalID);
  }
  render() {
    return (
      <div>
            <h1>Hello World!</h1>
            <h2>It is {this.state.time} !</h2>
        </div>
    );
  }
} 

export default Timer;

Notice I used two of React cycle functions componentDidMount and componentWillUnmount, in order to make the component update once again after finished mouting, and the other to clear the interval variable once react unmounts your component.

Upvotes: 3

Paul Fitzgerald
Paul Fitzgerald

Reputation: 12129

You can use React.useEffect passing an array as second argument, which is the equivalent of componentDidMount.

You then want to use setInterval to set the state every second.

Return a function from useEffect to clear the interval when the component unmounts.

See working codesandbox here.

You code would look as follows:

const function Timer() {
  const [time, setTime] = React.useState(null);
  React.useEffect(() => {
    const tick = () => {
      return new Date().toLocaleTimeString().toString();
    };
    const intervalId = setInterval(() => {
      setTime(tick());
      return () => clearInterval(intervalId);
    }, 1000);
  }, []);

  return <h2>It is {time} !</h2>;
}

Upvotes: 2

Set the date field to the state object and in tick function use setInterval to set a new value to state using setState. Use state.date value to show the time. React renders new dom each time state is changed using setState function.

A working example of a timer has been given in react docs, giving it a read will help you lots. https://reactjs.org/docs/state-and-lifecycle.html

Upvotes: 1

Related Questions