일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 솔로드릴
- 영화리뷰
- 드릴
- 주짓수
- development
- Express
- 주짓떼로
- 자바스크립트
- 하프가드
- 리액트
- 웹개발
- graphQL
- 노드
- 클로즈가드
- 프로그래밍
- nodejs
- Redux
- git
- 개발
- 파이썬
- Node
- 엄티로드
- REACT
- 디자인패턴
- 주짓떼라
- 영화감상
- JavaScript
- 개발자
- 영화
- web
- Today
- Total
As i wish
[React 반응속도 체크] 조건문 및 타이머 본문
안녕하세요. 오늘은 '반응속도 체크' 게임을 만들어 보겠습니다.
앞서 계속해서 언급했지만 제 포스팅은 '제로초' 님의 유투브 강좌를 듣고 복습하는 내용으로 꾸며집니다.
오늘은 '반응속도 체크' 게임을 통하여 jsx 안에서 조건문, 그리고 타이머에 관하여 공부했습니다.
일단 결과창 부터 확인해 보겠습니다.
이렇게 상태가 총 3가지 정도가 있고 파랑 -> 빨강 -> 초록 에 따라서 클릭 했을 때에 변화를 주는거죠.
먼저 파랑(waiting) 일때 클릭하면 빨강(ready)화면이 됩니다. 그 다음 특정 시간이 지나면 초록(now) 화면이 되는데 이 때, 화면을 클릭해서 반응속도를 체크하는거죠. 물론 빨강(ready) 화면일 때 누르면 경고 메세지를 알려주도록 합니다.
자, 그럼 코드를 확인해 보겠습니다.
일전에 리액트 프로젝트 세팅은 포스팅을 하였기 때문에 그걸 보시고 따라하시면 될듯 합니다.
ResponseCheck.jsx
import React, { Component } from 'react';
class ResponseCheck extends Component {
state = {
state: 'waiting',
message: 'Click to start.',
result: []
};
clickTimer;
startTime;
endTime;
onClickScreen = () => {
const { state, message, result } = this.state;
if (state === 'waiting') {
// waiting 일 때 클릭시 타이머를 돌려서 랜덤하게 now 화면으로 변하게 해준다.
this.clickTimer = setTimeout(() => {
this.setState({
state: 'now',
message: 'Click now'
});
}, Math.floor(Math.random() * 1000) + 2000); // Random 2~3 second
this.startTime = new Date();
this.setState({
state: 'ready',
message: 'Click to when screen is green.'
});
} else if (state === 'ready') {
// ready 일 때 클릭시 타이머를 초기화 해주고 경고 메세지를 보여준다.
clearTimeout(this.clickTimer);
this.setState({
state: 'waiting',
message: 'So fast, Please click when screen is green.'
});
} else if (state === 'now') {
// now 일 때 클릭시 클릭 한 시간을 저장하고 그 차이를 저장하여 반응속도 시간을 구한다.
this.endTime = new Date();
this.setState((prevState) => {
return {
state: 'waiting',
message: 'Click to start.',
result: [...prevState.result, this.endTime - this.startTime]
}
});
}
}
renderAverage = () => {
const { result } = this.state;
return result.length === 0 ? null : <><div>Average time: {(result.reduce((a, b) => a + b)) / result.length}</div></>
}
render() {
const { state, message, result } = this.state;
return (
<>
<div
id="screen"
className={state}
onClick={this.onClickScreen}
>
{message}
</div>
{this.renderAverage()}
</>
);
}
}
export default ResponseCheck;
자세한 설명은 코드에 있습니다.
index.html 에는 style태그를 추가하여 스크린 색이 바뀌도록 설정하였습니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>ResponseCheck</title>
<style>
#screen {
width: 300px;
height: 200px;
text-align: center;
user-select: none;
}
#screen.waiting {
background-color: aqua;
}
#screen.ready {
background-color: red;
color: white;
}
#screen.now {
background-color: greenyellow;
}
</style>
</head>
<body>
<div id="root"></div>
<!-- 웹팩으로 빌드한 ./dist/app.js 파일 -->
<!-- <script src="./dist/app.js"></script> -->
<!-- webpack-dev-server 사용시 dist 폴더 사용 안함 -->
<!-- but webpack.config.js 에서 publicPath 사용시 dist 폴더 사용 가능 -->
<script src="./app.js"></script>
</body>
</html>
client.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { hot } from 'react-hot-loader/root';
import ResponseCheck from './ResponseCheck'; // Class 사용
import ResponseCheckHook from './ResponseCheckHook'; // Hooks 사용
// const Hot = hot(ResponseCheck);
const Hot = hot(ResponseCheckHook);
ReactDOM.render(<Hot />, document.getElementById('root')); // Class 사용
마지막으로 reponseCheck 를 hooks 로 변환한 코드
ResponseCheckHook.jsx
import React from 'react';
const { useState, useRef } = React;
const ResponseCheckHook = () => {
const [state, setState] = useState('waiting');
const [message, setMessage] = useState('Click to start.');
const [result, setResult] = useState([]);
// useRef 는 DOM에서도 사용하지만 값이 변한다 해도 rendering이 되지 않는다.
// useState 는 값이 변하면 rendering 이 다시 되기 때문에
// 값이 변해도 rendering 이 필요 없는 변수는 useRef로 사용한다.
const clickTimer = useRef(null);
const startTime = useRef(0);
const endTime = useRef(0);
const onClickScreen = () => {
if (state === 'waiting') {
clickTimer.current = setTimeout(() => {
setState('now');
setMessage('Click now');
}, Math.floor(Math.random() * 1000) + 2000); // Random 2~3 second
startTime.current = new Date();
setState('ready');
setMessage('Click to when screen is green.');
} else if (state === 'ready') {
clearTimeout(clickTimer.current);
setState('waiting');
setMessage('So fast, Please click when screen is green.');
} else if (state === 'now') {
endTime.current = new Date();
setState('waiting');
setMessage('Click to start.');
setResult((prevResult) => {
return [...prevResult, endTime.current - startTime.current];
});
}
};
const renderAverage = () => {
return result.length === 0 ? null : <><div>Average time: {(result.reduce((a, b) => a + b)) / result.length}</div></>
}
return (
<>
<div
id="screen"
className={state}
onClick={onClickScreen}
>
{message}
</div>
{renderAverage()}
</>
);
}
export default ResponseCheckHook;
여기서 주의하실 점은 바로 useState 와 useRef 의 차이인데요. 코드에 적혀있습니다.
앞서 ResponseCheck.jsx 나 ResponseCheckHook.jsx 에서 renderAverage() 부분이 있는데 이는 조건문을 사용하기 위함입니다.
물론 react 내에 render 부분 안에서 if 문이 사용은 할 수 있으나 이는 복잡하여 이렇게 삼항 연산자를 사용합니다.
* 삼항 연산자
a = b === true ? "YO" : "WOW";
이런식으로 되어 있을 때에 a 의 값은 b 가 true 이면 "YO", false 이면 "WOW" 입니다.
이를 if 문으로 바꾸면
if (b === true) {
a = "YO";
} else {
a = "WOW";
}
가 되죠 참 쉽죠?
무튼 오늘도 이렇게 새로운 웹게임을 만들고 조건문에 대하여 하나 배웠네요.
마지막으로 hooks에서 useRef 를 사용하는 변수에 대해서는 변수면.current 를 붙여서 사용해야 합니다.
위 코드에서도 clickTimer 변수에 .current를 붙여서 사용한것을 확인할 수 있죠.
clickTimer.current = setTimeout(() => {
setState('now');
setMessage('Click now');
}, Math.floor(Math.random() * 1000) + 2000); // Random 2~3 second
그럼 오늘도 20000
ResponseCheck folder structure
'React JS' 카테고리의 다른 글
[React 가위, 바위, 보] 라이프 사이클 (0) | 2019.07.08 |
---|---|
[React JS] 프로젝트 셋팅 및 webpack, hot loader적용 (0) | 2019.07.08 |
[React 숫자 야구] props 와 component 분리 (0) | 2019.06.21 |
[React 끝말잇기] webpack-dev-server 및 react-hot-loader (0) | 2019.06.13 |
[React 끝말잇기] React 끝말잇기 (0) | 2019.06.13 |