티스토리 뷰

구조분해 문법으로 적어줘야 깔끔해짐

 

render의 return안에서는 for과 if를 쓸 수 없음

JSX에서는 쓸 수 없음!

 

그래서 리액트 조건문은 삼항연산자로 많이 씀!

  renderAverage = () => {
    const { result } = this.state;
    return result.length === 0
      ? null :
      <div>평균 시간: {result.reduce((a, c) => a + c) / result.length}ms</div>
      // 한번도 시도를 안했으면 태그가 없고:
      // 시도를 한 순간부터 평균시간을 보여줌
  };

JSX에서는 null, undefined은 태그가 없는 것으로 인식됨


// 삼항연산자 사용
const renderAverage = () => {
      return result.length === 0
        ? null :
        <>
          <div>평균 시간: {result.reduce((a, c) => a + c) / result.length}ms</div>
          <button onClick={onReset}>Reset</button>
        </>
  }

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

 

굳이 if나 for을 쓰고 싶다면 {}안에 자바스크립트를 사용할 수 있는 원리를 사용해서 즉시 실행함수를 만들면 됨

> 그러나 코드가 지저분해져서 비추

// return 안에 if 사용
return (
    <>
      <div id="screen"
        className={state} onClick={onClickScreen}
      >
        {message}
      </div>
      {(()=>{
      if (result.length === 0) {
        return null;
      } else {
        return <>
          <div>평균 시간: {result.reduce((a, c) => a + c) / result.length}ms</div>
          <button onClick={onReset}>Reset</button>
        </>
      }
      })()}
    </>
  )

for도 위와 같음

 

이런 경우는 자식 컴포넌트로 만들거나 함수로 빼는 것을 추천

+

반복문을 기점으로 자식 컴포넌트로 분리하기 좋음


불필요한 렌더가 발생하는 부분이 있는데

어쩔수없이 통째로 렌더가 다시 일어난다면 컴포넌트로 분리하는 것이 좋은 방법


반응속도 체크 만들기

// class
import React, { Component } from 'react';

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

  timeout; // 타임아웃 선언

  startTime;
  endTime;

  onClickScreen = () => {
    const { state, message, result } = this.state;
    if (state === 'waiting') {
      this.setState({
        state: 'ready',
        message: '초록색이 되면 클릭하세요.',
      });
      this.timeout = setTimeout(() => {
        this.setState({
          state: 'now',
          message: '지금 클릭!',
        })
        this.startTime = new Date();
      }, Math.floor(Math.random() * 1000) + 2000); // 2-3초 랜덤
    } else if (state === 'ready') { // 성급하게 클릭
      clearTimeout(this.timeout); // 타임아웃이 초기화가 안되고 계속 실행되므로 타임아웃도 초기화
      this.setState({
        state: 'waiting',
        message: '너무 성급하셨습니다. 초록색이 되면 클릭하세요',
      })
    } else if (state === 'now') { // 반응속도 측정
      this.endTime = 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}>Reset</button>
      </>
    };

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

export default ResponseCheck;

 


useState와 useRef의 차이점

 

setState로 값을 바꾸면 return 부분이 다시 실행됨 > 렌더를 다시하게 됨

useRef로 값을 바꿔도 return이 다시 실행되지 않음 > 불필요한 렌더를 하지 않음

 

값이 바뀌어도 렌더링을 다시 시키고 싶지 않을 땐 useRef

또는 값이 바뀌기는 하지만 화면에 영향을 미치고 싶지 않을 때 useRef

예) timeOut, Interval 등이 주로 사용, 화면이 바뀌는건 원하지 않고 값은 바뀌는 것들 startTime, endTime


// hooks
import React, { useState, useRef } from 'react';

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

  const onClickScreen = () => {
    if (state === 'waiting') {
      setState('ready');
      setMessage('초록색이 되면 클릭하세요.');
      timeout.current = setTimeout(() => {
        setState('now');
        setMessage('지금 클릭!');
        startTime.current = new Date();
      }, Math.floor(Math.random() * 1000) + 2000);
    } 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]
      });
    }
  };

  const onReset = () => {
    setResult([]);
  }

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

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

export default ResponseCheck;

Ref는 무조건 current로 접근하는 것 잊지말기


JSX는 배열 안에 넣어서 return하는 것도 가능, key값 필수

return [
  <div key="사과">사과</div>
  <div key="배">배</div>
  <div key="바나나">바나나</div>
];

하지만 자주 사용하지는 않음

 

껍데기 태그를 더 많이 씀

return <>
  <div key="사과">사과</div>
  <div key="배">배</div>
  <div key="바나나">바나나</div>
</>;
728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
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
글 보관함