개발자

React 동작 원리와 관련된 질문

2024년 07월 23일조회 2,718

아래 코드에서 handleClick 실행 시 setPending으로 "ready"로 상태가 변경되면 렌더링되고 delay이후 "done"으로 변경되면 또 렌더링 되는 건 알고있습니다. 1. 여기서 비동기함수(위에서 delay)와 관련해 batch 렌더링이 적용되지 않는 이유를 react 공문 링크나 설명 가능하신 분 계신가요? 2. handleClick의 컨텍스트에서 setPending으로 상태가 변경되고 react의 render함수가 실행되고 이후 delay함수가 실행되고 그 다음 setPending이 실행, 다시 render함수가 실행되는 과정을 실행컨텍스트 관점에서 알고싶습니다.

1import { useState } from 'react';
2
3export default function RequestTracer() {
4  const [pending, setPending] = useState('init');
5
6  async function handleClick() {
7    setPending('ready');
8    await delay(3000);
9    setPending('done');
10  }
11
12  function delay(ms) {
13  return new Promise(resolve => {
14    setTimeout(resolve, ms);
15  });
16}
17
18  return (
19    <>
20      <h3>
21        Pending: {pending}
22      </h3>      
23      <button onClick={handleClick}>
24        Click     
25      </button>
26    </>
27  );
28}
이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.
profile picture
익명님의 질문

답변 1

인기 답변

김하림님의 프로필 사진

흥미로운 질문이네요. Batch 렌더링이 적용되지 않은 이유 / 실행 컨텍스트 관점에서 보는 handleClick 실행 순서 순서로 답변 드리겠습니다. ### Batch 렌더링이 적용되지 않은 이유 React Working Group의 Automatic batching for fewer renders in React 18(https://github.com/reactwg/react-18/discussions/21)를 보면, "if you have two state updates inside of the same click event, React has always batched these into one re-render."(동일한 클릭 이벤트 내에 두 개의 상태 업데이트가 있는 경우, React는 항상 이를 하나의 리렌더링으로 일괄 처리합니다.) 라고 나와있습니다. 그럼 `handleClick` 함수에 포함된 두 개의 상태 업데이트(`setPending`)도 일괄 처리되야 하는거 아닌가? 라고 생각하실 수 있는데, 실제로 실행해보면 pending 상태가 각각 두 번의 독립적인 리렌더링을 통해 화면에 그려지는 것을 확인할 수 있습니다. 왜 그럴까요? 이는 JavaScript 엔진이 `await delay(3000)` 구문을 실행할 때, `handleClick`을 콜스택에서 제거하고 React가 다음 할 일(렌더링)을 수행하기 때문입니다. 즉, `await`에 의해 함수 실행이 일시 중단되고 재개되는 과정에서 React의 배치 처리 컨텍스트가 끊어지게 되어, 두 상태 업데이트가 별도로 처리되는 것입니다. 이는 굉장히 자연스러운 동작으로 보입니다. 불필요한 리렌더링을 방지하고 퍼포먼스를 끌어올리는 게 Batching이 하는 일입니다. 오히려 해당 코드에서 각각의 상태 업데이트를 하나로 묶는다면 그건 메커니즘이 목적에 맞지 않게 동작하는 것이라고 볼 수 있습니다. ### 실행 컨텍스트 관점에서 보는 handleClick 실행 순서 1. `handleClick` 함수가 호출되어 실행 컨텍스트가 생성되고 콜 스택에 푸시됩니다. 2. `setPending('ready')`가 실행됩니다. 이 때 상태 업데이트가 스케줄링되지만, 아직 렌더링이 시작된 건 아닙니다. 3. `await delay(3000)`를 만나면: - 새로운 Promise가 생성되고 `setTimeout`이 호출됩니다. - `handleClick` 함수 실행을 멈추고, 콜 스택에서 해당 실행 컨텍스트가 제거됩니다. - 제어권이 이벤트 루프로 넘어갑니다. 4. 이벤트 루프는 마이크로태스크 큐와 태스크 큐가 비어있는 걸 확인합니다. 5. React는 스케줄링된 상태 업데이트(`setPending('ready')`)를 처리하고 렌더링을 수행합니다. 6. 3초 후, `setTimeout` 콜백이 태스크 큐에 추가됩니다. 7. 이벤트 루프가 앞에서 추가된 콜백을 가져와서 실행합니다. - Promise가 resolve되고 `handleClick` 함수 실행을 재개합니다. - 새로운 실행 컨텍스트가 생성되어 콜 스택에 푸시됩니다. 8. `setPending('done')`이 실행되어 새로운 상태 업데이트가 스케줄링됩니다. 9. `handleClick` 함수가 종료되고 해당 실행 컨텍스트가 콜 스택에서 제거됩니다. 10. React는 새로 스케줄링된 상태 업데이트(`setPending('done')`)를 처리하고 두 번째 렌더링을 수행합니다.

profile picture

익명

작성자

2024년 07월 24일

다소 불친절할 수 있는 질문에 이렇게 좋은 답변으로 돌려주셔서 감사합니다. 상세한 답변 덕분에 궁금했던 부분이 어느정도 해소되었습니다.

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

목록으로
키워드로 질문 모아보기

실무, 커리어 고민이 있다면

새로운 질문 올리기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!