[웹 게임을 만들며 배우는 React] 반응속도 체크 (리액트 조건문, setTimeout, 성능체크hook변환, return 내부 for if, 배열 return, 콜백함수)

안지수·2023년 3월 28일
0
post-custom-banner

👑 React 조건문

-> 삼항 연산자 (조건부 연산자)로 !!

-> if는 따로 안 써줌

👑 setTimeout

: 일정 시간 후 코드를 비동기적으로 실행

  • 동기와 비동기 차이
    -> 데이터를 받는 방식은 동기와 비동기로 나뉜다.
  • 동기: 데이터의 요청과 결과가 한 자리에!
    ex) 사용자가 서버에게 데이터를 요청한다면, 서버가 리턴값을 주기 전까지 다른 활동을 할 수 없다.
  • 비동기: 동시에 일어나지 않는다.
    ex)서버에게 데이터를 요청 한 후, 응답을 기다리지 않아도 되고 서버에게 다른 요청을 보내도 된다.

clearTimeOut()

-> 타이머를 사용했으면 클리어도 꼭 해줘야 함! 클리어하기 위해선, setTimeout의 반환값을 가지고 clearTimeout을 호출해야 합니다.

👑 반응속도체크 hook 변환

** class hook으로 변환 방법
: class이름, state들 const로 use 사용해서 변경-> return -> 각 함수들 const로 화살표 함수로 표현 -> this.state 없애줌 (setResult..etc) hook 사용하기!

-> 예전 state를 참고할 때!! prevState아니고!!!

  • class component 버젼
import React, { Component } from 'react';

class ResponseCheck extends Component {
  state = {
    state: 'waiting',
    message: '클릭해서 시작하세요.',
    result: [],
  };

  timeout;
  startTime;
  endTime;

  onClickScreen = () => {
    const { state } = this.state;
    if (state === 'waiting') {
      timeout.current = setTimeout(() => {
        this.setState({
          state: 'now',
          message: '지금 클릭',
        });
        this.startTime = new Date();
      }, Math.floor(Math.random() * 1000) + 2000); // 2초~3초 랜덤
      this.setState({
        state: 'ready',
        message: '초록색이 되면 클릭하세요.',
      });
    } else if (state === 'ready') { // 성급하게 클릭
      clearTimeout(this.timeout);
      this.setState({
        state: 'waiting',
        message: '너무 성급하시군요! 초록색이 된 후에 클릭하세요.',
      });
    } else if (state === 'now') { // 반응속도 체크
      endTime.current = new Date();
      this.setState((prevState) => {
        return {
          state: 'waiting',
          message: '클릭해서 시작하세요.',
          result: [...prevState.result, this.endTime, this.startTime],
        };
      });
    }
  };

  onReset = () => {
    this.setState({
      result: [],
    });
  };

  renderAverage = () => {
    const {result} = this.state;
    return result.length === 0
      ? null
      : <>
        <div>평균 시간: {result.reduce((a, c) => a + c) / result.length}ms</div>
        <button onClick={this.onReset}>리셋</button>
      </>
  };

  render() {
    const { state, message } = this.state;
    return (
      <>
        <div
          id="screen"
          className={state}
          onClick={this.onClickScreen}
        >
          {message}
        </div>
        {this.renderAverage()}
      </>
    )
  }
}

export default ResponseCheck;
  • hook 버젼
import React, { useState, useRef, useCallback, useMemo } from 'react';

const ResponseCheck = () => {
  const [state, setState] = useState('waiting');
  const [message, setMessage] = useState('클릭해서 시작하세요.');
  const [result, setResult] = useState([]);
  const timeout = useRef(null);
  const startTime = useRef(0);
  const endTime = useRef(0);

  const onClickScreen = useCallback(() => {
    if (state === 'waiting') {
      timeout.current = setTimeout(() => {
        setState('now');
        setMessage('지금 클릭');
        startTime.current = new Date();
      }, Math.floor(Math.random() * 1000) + 2000); // 2초~3초 랜덤
      setState('ready');
      setMessage('초록색이 되면 클릭하세요.');
    } else if (state === 'ready') { // 성급하게 클릭
      clearTimeout(timeout.current);
      setState('waiting');
      setMessage('너무 성급하시군요! 초록색이 된 후에 클릭하세요.');
    } else if (state === 'now') { // 반응속도 체크
      endTime.current = new Date();
      setState('waiting');
      setMessage('클릭해서 시작하세요.');
      setResult((prevResult) => {
        return [...prevResult, endTime.current - startTime.current];
      });
    }
  }, [state]);
  const onReset = useCallback(() => {
    setResult([]);
  }, []);

  const renderAverage = () => {
    return result.length === 0
      ? null
      : <>
        <div>평균 시간: {result.reduce((a, c) => a + c) / result.length}ms</div>
        <button onClick={onReset}>리셋</button>
      </>
  };

  return (
    <>
      <div
        id="screen"
        className={state}
        onClick={onClickScreen}
      >
        {message}
      </div>
      {renderAverage()}
    </>
  );
};

export default ResponseCheck;


setTimeout hook로 바꾸는 방법: ref로!!!

-> endtime.current 이런식으로, ref를 사용해 current로 접근해주면 된다!!

👑 state와 ref 차이 그리고 props

state: "컴포넌트 내에서 관리되는 데이터 객체"

컴포넌트 마운트 시 기본값을 가지고 생성, 변경 가능-보통 유저 이벤트 통해서 변경, 바뀌면 return 부분다시 렌더링 (return 실행)
1. 직접 state 값 변경: constructor에서만 가능 (렌더링x)
2. setState()를 사용해서 state가 변경 (렌더링)

ref: "DOM에 이름을 다는 것으로, DOM에 직접 접근하고 싶을 때 사용"

바뀌어도 렌더링 안됨 (return 실행 안됨)
--> 바뀌어도 렌더링 되지 않게 하고 싶으면 (화면에 영향 주고 싶지 않으면), ref에 넣어!! (useRef는 화면에 영향주지 않음)
!!ref는 무조건 current로 접근!!

  • props: properties의 줄임말/ 상위 컴포넌트로부터 전달되며, 값 변경 불가능!

---> 즉 state는 변경 시 즉시 렌더링이 되어야하는 값들을 다룰 때 사용, ref는 렌더링을 발생시키지 않아도 되는 값을 다룰 때 사용.

👑 return 내부에 for과 if문

-> 코드가 복잡해져서 그렇게 잘 쓰지 않음
(조건문은 삼항연산자, 반복문은 map으로 사용!!)


-> 사용하는 경우에는, 즉시 실행 화살표 함수 만들어주기!!
*배열을 return 하는 경우: key를 넣어줘야 함

⭕ 정리:
리액트 조건문은 삼항연산자로!! props는 부모 컴포넌트로부터 값을 전달 받음, ref는 dom에 이름 지정해주는 것 렌더링 안되는 값 다룰때, state는 setState로 값 변경 가능한데, 그럴 때마다 렌더링되므로 렌더링 필요한 값 다룰 때 사용. setTimeout은 반응 속도를 체크해주기 위한 함수이다. clear도 꼭 해주어야 한다는 것!!!

  • 콜백 함수: 함수 안에서 어떤 특정한 시점에 호출되는 함수. 함수의 매개변수로 전달하여 특정 시점에서 콜백 함수를 호출
  • useCallback: 리액트의 렌더링 성능을 위해 제공되는 hook이다. 특정함수를 새로 만들지 않고, 재사용하고 싶을 때 사용.

    -> 2개의 파라미터: 첫번째- 기존 함수/ 두번째- 함수 재생성할 기준, 위의 코드에서도 name이 변경될 때만 이 함수가 재생성된다는 것을 알 수 있다.
profile
지수의 취준, 개발일기
post-custom-banner

0개의 댓글