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:
- we put the
time_elapsed
state in a single component with no other state field in it.- start
hanler = setInterval()
to update thetime_elapsed
, incomponentDidMount()
stage - pass out the
handler
to its parent component
- start
- we also want the parent component can
startTimer
andstopTimer
- 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
- we need to get the handler of the
III. Implementation
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>