React에서 state의 batch 처리? (상태 일괄 업데이트?)

Soozynn·2022년 1월 31일
0

medium과 react 공식 문서를 통해 리액트의 일괄 처리가 어떻게 동작하는지 정리해보고자 한다.

이 부분을 짚어보기 전에 먼저 react의 setStateuseState가 어떤 방법으로 동작하는지부터 짚어볼 필요가 있을 것 같다.

리액트 공식문서에 의하면,

setState()가 하는 일은 컴포넌트의 state 객체에 대한 업데이트를 실행하고, state가 변경되면 컴포넌트는 리렌더링된다고 적혀있다.

나는 이전에 setState()가 즉각적인 요청이라고 생각하였고 변경되는 즉시 리렌더링 된다고 생각하였다. 하지만, 공식문서를 더 살펴보니

" setState()는 컴포넌트를 갱신하는 데에 있어 즉각적인 명령이 아니라 요청이라고 생각하시기 바랍니다. 인지 성능(Perceived Performance)의 향상을 위하여 React는 이 메서드의 실행을 지연시키고 여러 컴포넌트를 한번에 갱신할 수도 있습니다. React는 state 변화가 즉시 적용되는 것을 보장하지 않습니다. "

즉, setState()는 컴포넌트를 항상 즉각적으로 갱신하지는 않고, 오히려 여러 변경 사항과 함께 일괄적으로 갱신하거나, 나중으로 미룰 수도 있다는 것이다.
이로 인하여 setState()를 호출하자마자 state에 접근하는 것에도 잠재적인 문제가 있을 수 있다고도 한다.

다시한번 정리하자면,
React는 상태 값을 업데이트 할 때 모든 요청에 따라 바로바로 rerender가 되는것이 아닌 변경사항을 모아서 한번에 일괄 처리(batch update)를 하고, 이 일괄 업데이트를 통해 컴포넌트의 렌더링 횟수를 최소화하는 것이다. (성능 향상 측면)

-> 불필요한 렌더링 방지




또한, setState 는 이벤트 핸들러 내에서 비동기적으로 작동한다.

이로 인해 부모와 자식이 모두 click 이벤트에서 setState를 호출한다면 자식은 두 번 렌더링되지 않는 대신 React는 브라우저 이벤트가 끝날 시점에 state를 일괄적으로 업데이트하고, 이는 더 큰 규모의 앱에서 뚜렷한 성능 향상을 만들어낸다.

그렇다면, 언제, 어떻게 batch update가 일어날까?


import React, { useState, useEffect } from "react";

export default function App() {
  const [counter1, setCounter1] = useState(0);
  const [counter2, setCounter2] = useState(0);
  const [counter3, setCounter3] = useState(0);
  const [renderCount, setRenderCount] = useState(0);

  useEffect(() => {
    setRenderCount(renderCount + 1);
  }, [counter1, counter2, counter3]);

  const handleClick = () => {
    setCounter1(counter1 + 1);
    setCounter2(counter2 + 1);
    setCounter3(counter3 + 1);
  };

  return (
    <div className='App'>
      <h1>Function Component</h1>
      <div>
        Counter1: {counter1}
      </div>
      <div>
        Counter2: {counter2}
      </div>
      <div>
        Counter3: {counter3}
      </div>
      <br/>
      <div>Component was rendered {renderCount} times</div>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
}

해당 코드에서 Component was rendered 의 횟수는 처음 useEffect가 렌더링되는 횟수를 포함해서 1을 기점으로 한 번 클릭시 +1씩 증가한다.

생각과 달리 클릭 시 구성 요소는 세 가지 상태가 별도로 변경되지만 한 번만 렌더링되고, 이는 일괄 업데이트 덕분에 가능한 것이다.

예외 케이스)

이벤트 핸들러가 비동기 처리 방식으로 실행될 경우
-> async/await, then/catch, setTimeout, fetch 등

일괄 처리가 모든 상황에서 작동하는 것은 아니다. 위와 같이 예외 상황도 존재한다.

추가 내용)

  • 17과 18버전의 차이

로딩 스테이트가 컴포넌트 안에서 밖으로 따로 분류됨 -> suspence / 서버 사이드 렌더링

<App>
   <Header />
   <Posts />
<App />

위와 같은 코드 예시에서 현재는 posts가 렌더링 될 때까지 헤더는 보이지 못하는 문제가 있을 수 있다.
하지만 18버전에서부터는, 느린 컴포넌트를 기다릴 필요 없이 서스펜스를 이용해 애플리케이션을 빠르게 렌더링 할 수 있게 되었다.
느린 컴포넌트가 백엔드에서 로딩 되고 나면, 리액트가 이것을 프론트로 보내서 http stream을 사용해 스크린에 띄워주는 형태이다.

서버 컴포넌트?
백엔드에서 존재하는 react js 코드를 쓸 수 있게 되어진다

  • 서버가 렌더링할 컴포넌트인지 클라이언트가 렌더링할 컴포넌트인지 미리 선택할 수 있음
    -> 이는 로딩 타임이 더 빨라지고 ux가 더 향상된다는 장점을 가져다준다.

  • 디비랑 직접적으로 커뮤니케이션 하는 리액트 컴포넌트가 생긴다.
    파일 이름 끝에 server와 client를 작성해주는 방식 / 범용은 이전 그대로

react 18부터는 렌더링 엔진이 동시 렌더링으로 변경 되었다..

0개의 댓글