React Rendering을 나만의 언어로 이해한 경험

moai·2020년 11월 8일
2
post-thumbnail

여러분들은 렌더링을 뭐라고 생각하시나요?

어떤 조건에서 렌더링이 일어 나는 지에 대해 알아보고,

렌더링을 나만의 언어로 이해 해본 경험을 나눠 볼까 합니다.

렌더링이란?

리액트에서의 렌더링은 생각해보면,

특정 조건에서 DOM Tree를 업데이트 하는 것으로 볼 수 있습니다.

어떤 조건에서 렌더링이 일어날까요?

  1. Props 가 변경 되었을 때
  2. State 가 변경 되었을 때
  3. forceUpdate() 함수를 실행 하였을 때
  4. 부모 컴포넌트가 렌더링 되었을 때

리액트는 위와 같은 조건에서 렌더링이 일어납니다.

그렇다면, 문제를 하나 내보겠습니다.

function Counter() {
  const [count, setCount] = useState(0);
  function handleAlertClick() {
    setTimeout(() => {
      alert('You clicked on: ' + count);
    }, 3000);
  }
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
      <button onClick={handleAlertClick}>
        Show alert
      </button>
    </div>
  );
}

위와 같은 코드가 있습니다.
아래와 같은 동작을 실행 시켰을 때,

  • 카운터를 3으로 증가시킨다
  • “Show alert” 을 누른다
  • 타임아웃이 실행되기 전에 카운터를 5로 증가시킨다

결과는 어떻게 될까요?

You clicked 3 times

You clicked 5 times

둘 중에 어떤 결과가 나올까요?
직접 해봅시다!

문제 1

왜 3이 출력될까요?
이를 이해하기 위해서는 한 가지 재밌는 발상을 해 볼 수 있습니다.

랜더링을 하나의 스크린 샷으로 생각해야 한다.

입니다.

렌더링은 스크린 샷이라는 생각을 가지고 저희가 한 행동을 다시 한번 짚어 봅시다.

사진 1

  1. A 스크린 샷에 있을 때 버튼을 클릭해서 count 라는 상태를 변경해서 렌더링이 일어났습니다.
    (count === 0 → count === 1)

  2. B 스크린 샷에 있을 때 버튼을 클릭해서 count 라는 상태를 변경해서 렌더링이 일어났습니다.
    (count === 1 → count === 2)

  3. C 스크린 샷에 있을 때 버튼을 클릭해서 count 라는 상태를 변경해서 렌더링이 일어났습니다.
    (count ===2 → count === 3)

  4. D 스크린 샷에 있을 때, alert 버튼을 클릭 했습니다.
    (count === 3)

  5. D 스크린 샷에 있을 때 버튼을 클릭해서 count 라는 상태를 변경해서 렌더링이 일어났습니다.
    (count === 3 → count === 4)

  6. E 스크린 샷에 있을 때 버튼을 클릭해서 count 라는 상태를 변경해서 렌더링이 일어났습니다.
    (count ===4 → count ===5)

저희는 (4) 번에서 alert 버튼을 클릭해서, 그 때의 상태를 조회 했습니다.

그 때의 count의 값은 3 입니다.

렌더링은 스크린 샷 이기 때문에,

alert 버튼을 클릭하면 그때 그 당시의 count값을 조회합니다.
그래서 3이 나오는 것입니다.

위와 같은 실험 결과로 아래와 같은 생각을 해볼 수 있습니다.

상태는 스크린 샷 들을 관통하는 하나의 값이 아니라,

상태는 스크린 샷에 갇힌 하나의 값에 불과 하다.

이벤트 핸들러 또한 스크린 샷에 갇힌 하나의 값에 불과 하다.

위와 같은 생각을 useCallback 함수에 똑같이 대입해 볼게요.

useCallback

useCallback의 간단한 정의입니다.

useCallback(func, deps);

해석 해보면,

리액트는 랜더링이 될 때 마다, 함수를 다시 만들어.

근데, 난 이 함수를 다시 만들기가 싫어!

그니깐 나는 특정 값이 바뀌지 않을때는 이 함수를 다시 만들지 않을 거야!

그러면, 너는 나한테 특정 값을 알려줘.

내가 특정 값이 바뀌었을 때만 다시 함수를 다시 만들게!

이런 내용의 Hook 인데요,

이를

렌더링은 스크린샷이다!

라는 원칙에 대입해서 해석해 볼게요.

문제를 또 하나 내 보겠습니다.

위와 같은 컴포넌트가 있습니다.

버튼을 3번 클릭 했을 때, 어떤 결과가 나올까요?

문제 2

직접 해봅시다.

이를 그림으로 이해해 봅시다.

  1. A 스크린 샷에 있을 때 버튼을 클릭해서 appleNum 이라는 상태를 변경해서 렌더링이 일어났습니다.
    하지만, useCallback 으로 둘러 쌓여진 getApples() 함수는 재활용 합니다.
    (appleNum === 1 → appleNum === 2)

  2. B 스크린 샷에 있을 때 appleNum은 2 입니다.
    하지만, getApples() 는 A 스크린 샷에 존재합니다.
    A 스크린 샷에서 appleNum은 1이기 때문에, 사과는 한개만 돌려줍니다.
    B 스크린 샷에서 appleNum 이라는 상태를 변경해서 렌더링이 일어납니다.
    (appleNum === 2 → appleNum === 3)

  3. C 스크린 샷에 있을 때 appleNum은 3 입니다.
    하지만, getApples() 는 A 스크린 샷에 존재합니다.
    A 스크린 샷에서 appleNum은 1이기 때문에, 사과는 한 개만 돌려줍니다.

저는 이런 방법으로 리액트의 랜더링상태를 이해했습니다.

제가 잘못 이해 한 것이 있거나, 잘못된 정보가 있다면 꼭 알려 주시길 바랄게요!

참고한 글
[번역] useEffect 완벽 가이드

4개의 댓글

comment-user-thumbnail
2020년 11월 12일

잘 읽었습니당

1개의 답글
comment-user-thumbnail
2020년 12월 1일

오... useCallback 완전 이해 갑니다ㅠㅠ 다시 함수를 부르지 않는다, 이 부분이 긴가민가했는데 사과 예시로 확 이해했습니다!!

1개의 답글