A Way to Make an Efficient React Timer

I. The Problem

It is very common we need to implement a Timer in our daily projects. Of course, there are several ways to make one.

Most online resource only introduces how to make a Timer as the only one component itself, while in reality we want our Timer to be an sub-component of some parent component

We don’t want to put the time_elapsed state in the state of its parent component. That way, every one seconds, the parent component will rerender over and over, even though all other state field stay the same.

II. We Want Efficiency

Here, the basic idea is:

  1. we put the time_elapsed state in a single component with no other state field in it.
    • start hanler = setInterval() to update the time_elapsed , in componentDidMount() stage
    • pass out the handler to its parent component
  2. we also want the parent component can startTimer and stopTimer
    • we need to get the handler of the setInterval(), in order to stop it in outside
    • BUT, how to get the handler??? ==> we pass in an object as props to timer component

III. Implementation

  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    <html>
    <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
    </head>
    <body>
    <div id="root"></div>
    <script type="text/jsx">

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

    componentDidMount (){
    this.props.timerObj.handler = setInterval(()=>{
    this.setState({ currTime: this.state.currTime+1000 })
    }, 1000)
    }

    render(){
    console.log("Inside Timer Component: ", this.state)
    const timePassed = this.state.currTime / 1000
    return <span>{timePassed}</span>
    }
    }


    class App extends React.Component{
    constructor(props){
    super(props)
    this.state = { showTimer: false }
    this.timerObj = { handler: null }
    }

    startTimer = ()=>{
    this.setState({ showTimer: true })
    }

    stopTimer = ()=>{
    clearInterval(this.timerObj.handler)
    this.setState({showTimer: false})
    }


    render(){
    console.log("App Component: ", this.state)
    const TimerPlaceholder = this.state.showTimer ? <Timer timerObj={this.timerObj} /> : null
    return (
    <div>
    <h1> React Inner Timer Component</h1>
    <button onClick={this.startTimer}> startTimer </button>
    <br /><br />

    Time Passed: {TimerPlaceholder }

    <br /><br />
    <button onClick={this.stopTimer}> stopTimer </button>
    </div>
    )
    }
    }


    ReactDOM.render(
    <App />,
    document.getElementById('root')
    );
    </script>
    </body>
    </html>