As i wish

[React 반응속도 체크] 조건문 및 타이머 본문

React JS

[React 반응속도 체크] 조건문 및 타이머

어면태 2019. 7. 4. 16:48

안녕하세요. 오늘은 '반응속도 체크' 게임을 만들어 보겠습니다.

앞서 계속해서 언급했지만 제 포스팅은 '제로초' 님의 유투브 강좌를 듣고 복습하는 내용으로 꾸며집니다.

 

제로초님의 웹게임 강좌

 

리액트 무료 강좌(웹게임) - YouTube

 

www.youtube.com

 

오늘은 '반응속도 체크' 게임을 통하여 jsx 안에서 조건문, 그리고 타이머에 관하여 공부했습니다.

일단 결과창 부터 확인해 보겠습니다.

이런식으로 파란 화면이 waiting
빨간 화면이 ready
초록 화면으로 되면 빠르게 눌러서 반응속도 체크
빨간화면일 때 잘못 누르면 경고 메세지

이렇게 상태가 총 3가지 정도가 있고 파랑 -> 빨강 -> 초록 에 따라서 클릭 했을 때에 변화를 주는거죠.

먼저 파랑(waiting) 일때 클릭하면 빨강(ready)화면이 됩니다. 그 다음 특정 시간이 지나면 초록(now) 화면이 되는데 이 때, 화면을 클릭해서 반응속도를 체크하는거죠. 물론 빨강(ready) 화면일 때 누르면 경고 메세지를 알려주도록 합니다.

 

자, 그럼 코드를 확인해 보겠습니다.

일전에 리액트 프로젝트 세팅은 포스팅을 하였기 때문에 그걸 보시고 따라하시면 될듯 합니다.

 

리액트 프로젝트 세팅

 

[React 구구단] React 프로젝트 셋팅

안녕하세요. 엄티 입니다. 이제부터 React를 사용해서 간단한 구구단 게임을 만들어 보겠습니다. 그전에 React를 사용하기 위한 간단한 프로젝트 세팅을 해보겠습니다. 참고로 제 포스팅 유명하신 '제로초'님 강좌..

eomtttttt-develop.tistory.com

webpack, hotloader 세팅

 

[React 끝말잇기] webpack-dev-server 및 react-hot-loader

안녕하세요. 엄티 입니다. 오늘은 리액트 프로젝트를 만들 시에 코드 수정과 함께 자동으로 결과창이 변할 수 있도록 세팅을 한번 해보겠습니다. 사실 앞선 포스팅에서는 계속해서 코드를 바꾸고, webpack 빌드를..

eomtttttt-develop.tistory.com

 

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

Comments