– prerequisite
+ 자바스크립트는 싱글 쓰레드이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 자바스크립트 실행순서 알기: 싱글쓰레드이다. // 코드를 모두 실행하고 마지막에 예약된 큐를 확인해서 실행한다. // 따라서 실행결과는 항상 동일하다. console.log("A"); //예약 setTimeout(function () { console.log("B"); }, 0); console.log("C"); //만일 루프가돌면? // while(true) {} //예약목록 확인 및 실행 |
Stopwatch 화면구성
1 2 3 4 5 6 7 8 9 10 11 12 |
class Stopwatch extends Component { render() { return ( <div className="stopwatch"> <h2>Stopwatch</h2> <span className="stopwatch-time">0</span> <button>Start</button> <button>Reset</button> </div> ) } } |
Header 컴포넌트에 Stopwatch 컴포넌트를 추가한다.
1 2 3 4 5 6 7 8 9 |
const Header = (props) => { return ( <header> <Stats players={props.players} /> <h1>{ props.title }</h1> <Stopwatch /> </header> ) } |
전체 logic 구성
DOM이 렌더링 된 직후에 호출되는 componentDidMount 라이프 사이클 메서드와 DOM이 파괴직전 호출되는 componentWillUnmount 라이프 사이클 메서드에 리소스 할당 해제하는 코드를 추가한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
... tickRef; ... // DOM이 렌더링 된 직후에 호출되는 라이프 사이클 // 3rd 라이브러리 로딩, 네트워크 호출 componentDidMount() { this.tickRef = setInterval(this.tick, 1000); } // DOM이 파괴되기 직전에 호출되는 라이프 사이클 // 리소스 해제 등등 componentWillUnmount() { clearInterval(this.tickRef); } |
start stop 토글 버튼 – 조건부 렌더링
시간에 따라 변하는 변수인 isRunning 변수를 추가하고 stop start 토글 버튼을 구현한다.
isRunning 변수에 따라서 Stop 버튼 혹은 Start 버튼이 나타나는데 이것을 conditional rendering 이라고 한다.
컨디셔널 렌더링은 뷰에서는 v-if 앵규러에서는 ng-if 라는 별도의 템플릿이 있는 만큼 굉장히 많이 사용되는 문법이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Stopwatch extends Component { state = { isRunning: false } handleStopwatch = () => { this.setState(prevState => ({isRunning: !prevState.isRunning})); } render() { return ( <div className="stopwatch"> <h2>Stopwatch</h2> <span className="stopwatch-time">0</span> <button onClick={this.handleStopwatch}>{this.state.isRunning ? 'Stop' : 'Start'}</button> <button>Reset</button> </div> ) } } |
timer logic
tick 함수에 isRunning 상태에 따라 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 |
class Stopwatch extends Component { tickRef; state = { isRunning: false, timer: 0 } tick = () => { // isRunning이 true이면 timer를 1씩 증가 if (this.state.isRunning) { this.setState(prevState => ({ timer: prevState.timer + 1 })) } } handleStopwatch = () => { this.setState(prevState => ({isRunning: !prevState.isRunning})); } // DOM이 렌더링 된 직후에 호출되는 라이프 사이클 // 3rd 라이브러리 로딩, 네트워크 호출 componentDidMount() { this.tickRef = setInterval(this.tick, 1000); } // DOM이 파괴되기 직전에 호출되는 라이프 사이클 // 리소스 해제 등등 componentWillUnmount() { clearInterval(this.tickRef); } render() { return ( <div className="stopwatch"> <h2>Stopwatch</h2> <span className="stopwatch-time">{this.state.timer}</span> <button onClick={this.handleStopwatch}>{this.state.isRunning ? 'Stop' : 'Start'}</button> <button>Reset</button> </div> ) } } |
reset 로직
리셋 버튼은 단순히 timer를 0으로 초기화하면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
handleReset = () => { this.setState({timer: 0}); } render() { return ( <div className="stopwatch"> <h2>Stopwatch</h2> <span className="stopwatch-time">{this.state.timer}</span> <button onClick={this.handleStopwatch}>{this.state.isRunning ? 'Stop' : 'Start'}</button> <button onClick={this.handleReset}>Reset</button> </div> ) } |
lifecycle 종료시
해당 컴포넌트가 종료시 setInterval로 생성한 id를 초기화한다.
1 2 3 4 5 |
tickRef; componentWillUnmount() { clearInterval(this.tickRef); } |
-note
+ adding Lifecycle Methods to a Class