React 18 주요 변경점

2024. 4. 15. 11:54·React

Automatic Batching

상태 업데이트(setState)를 하나로 통합해서 배치처리를 한 후 리렌더링을 진행합니다.
→ 리렌더링 관련 성능 개선

 

v17 에서는: 이벤트 핸들러 내부에서 발생하는 상태 업데이트 시 fetch()등 과 같은 콜백을 받아 처리하는 메소드가 존재할 경우에는 Automatic Batching이 처리되지 않았습니다.

// v17 & v18: 2가지 상태 업데이트가 이루어졌지만 1번의 리렌더링 발생
const onClick = () => {
    setNumber((prev) => prev + 1);
    setBoolean((prev) => !prev);
};

---
// v17: 2번의 리렌더링 발생
// v18: 1번의 리렌더링 발생
const onClick = () => {
    // fetch()를 활용해서 콜백함수 내부에서 여러개의 상태 업데이트
    fetch("<https://jsonplaceholder.typicode.com/posts/1>").then((response) => {
      setNumber((prev) => prev + 1);
      setBoolean((prev) => !prev);
    });
};

결론적으로 Automatic Batching이 버전에 따라 다음과 같이 적용됩니다.

v17

  • 콜스택에서 적용됨
  • 테스크큐에서 적용되지 않음

v18

  • 콜스택 & 테스크큐 모두 적용됨
  • ❗️v18에서도 아래 경우에는 적용되지 않습니다.
// 콜스택과 테스크큐에서 상태 업데이트를 각각 진행할 경우 2번의 리렌더링이 발생
const onClick = () => {
    setNumber((prev) => prev + 1);
    fetch("<https://jsonplaceholder.typicode.com/posts/1>").then((response) => {
      setBoolean((prev) => !prev);
    });
  };

 

Automatic Batching을 적용시키고 싶지 않다면

  • react-dom의 flushSync()를 활용하여 Automatic Batching 기능을 off 할 수 있습니다.
const onClick = () => {
    // flushSync() 활용
    flushSync(() => {
      setNumber((prev) => prev + 1);
    });
    flushSync(() => {
      setBoolean((prev) => !prev);
    });
};

Concurrent Feature(동시성 기능)

v18부터 기존 React에서 추구하고 있는 Concurrent Mode를 ‘기능'으로 지원합니다.

 

→ 자바스크립트는 싱글 스레드기반 언어이므로, React에서도 UI 렌더링 도중에 일어나는 모든 작업은 차단됩니다.

이를 Concurrent Mode를 사용해 여러 작업을 동시에 처리할 수 있도록 기능들을 확대하고 있었습니다.

  1. 작업들을 작은 단위로 나눈 후 작업들 간의 우선순위를 정합니다.
  2. 정해진 우선순위에 따라 작업을 수행합니다.
  3. 실제로는 동시에 작업이 수행되지는 않지만 작업 간의 전환이 매우 빠르기 때문에 동시에 수행되는 것처럼 보입니다.

→ Concurrent Mode를 적용하려면 다음과 같은 방법을 사용합니다.

  1. useLayoutEffect를 사용하여 컴포넌트의 렌더링이 완료된 후에도 실행시켜 리렌더링 될 때까지 컴포넌트의 이전 렌더링 결과를 유지하게 합니다.
  2. useState를 사용하여 컴포넌트의 렌더링 상태를 추적(isLoading: true/false)합니다. 컴포넌트의 렌더링 상태를 추적하여, 렌더링이 완료될 때까지 컴포넌트의 이전 렌더링 결과를 유지하게 합니다.

createRoot

기존 v17의 render()가 아닌createRoot()를 사용합니다.

// v17
ReactDOM.**render**(<App />, document.getElementById("root"));

// v18
const container = document.getElementById("root");
const root = **createRoot**(container);
root.render(<App />);

 

startTransition

디바운스 / 쓰로틀링 / setTimeout 등의 기능을 대체합니다.
(v18 이전에는 디바운스, 쓰로틀링, setTimeout으로 우선순위가 낮은 업데이트를 제어했습니다.)

  • 자바스크립트의 setTimeout 동작방식과 달리 테스크큐를 활용하지 않으며 동기적으로 즉시 실행합니다.
  • useTransition
    • isPending: state 변경 직후에도 UI를 리렌더링 하지 않고 UI를 잠시 유지하는 상태입니다.
    • startTransition: 우선순위가 높은 상태 업데이트가 발생할 경우 내부에 선언한 상태 업데이트는 중단되고 이후에 해당 상태 업데이트가 발생합니다.
const [isPending, startTransition] = useTransition({
	priority: 0.5
});
const [boolean, setBoolean] = useState();

const onClick = () => {
  startTransition(() => {
    setBoolean((prev) => !prev);
  });
};

 

Suspense와 SSR

기존 React에서의 SSR 적용은 waterfall 방식을 사용하고 있었습니다.

  1. React 코드를 서버에서 실행합니다.
  2. React 코드가 HTML을 생성합니다.
  3. HTML을 클라이언트에게 전송합니다.
  4. 클라이언트는 HTML을 렌더링합니다.
  5. HTML에 자바스크립트가 Hydrate 됩니다.

v18 부터는 독립적으로 각각 렌더링이 가능한 기능이 추가 되었습니다.

  • 기존의 createRoot 대신 hyrateRoot 사용

HTML Streaming

  • HTML을 서버에서 클라이언트로 전송할 때, 전체 HTML을 한 번에 전송하지 않고, 부분적으로 전송합니다.
  • pipeToNodeWritable()를 활용해 HTML코드를 작은 청크로 나눈 후 보내줄 수 있습니다.
    *기존의 React는 renderToString()을 사용했습니다.

Selective hydrating

  • <Suspense> 를 활용하여 해당 컴포넌트가 아직 렌더링되지 않아도 다른 컴포넌트들이 hydration을 시작할 수 있습니다.

먼저 hydration이 완료된 컴포넌트는 상호작용이 가능합니다.

  • hydration 시 fallback component를 지정할 수 있습니다.(fallback 속성)
  • hydration의 우선순위를 정할 수 있습니다.(preload 속성)
<>
    <Suspense fallback={<Spinner />} preload={true}>
        <Component1 />
    </Suspense>
    <Suspense fallback={<Spinner />} preload={false}>
        <Component2 />
    </Suspense>
</>
  • 사용자가 <Component1 />의 hydration이 완료되기 전 <Component2 />의 hydrationTrigger(클릭, 스크롤, 포커스 등)를 발생시킨다면 React는 <Component2 />의 우선순위를 높여 먼저 hydration을 진행합니다.

React Server Component(RSC)

  • 지정한 컴포넌트를 클라이언트가 아닌 서버에서 렌더링합니다.
  • .client.jsx, .server.jsx, .jsx 3개의 파일로 구성됩니다.
  • 서버 컴포넌트는 번들에 포함되지 않기 때문에 번들 사이즈가 감소합니다.
  • API 호출을 통해 여러 데이터를 불러올 필요 없이 DB 접근 / 파일 시스템 등을 접근할 수 있습니다.
  • 기존 lazy loading 방식을 자동으로 지원합니다.
// v17
const OldPhotoRenderer = React.lazy(() => import('./OldPhotoRenderer.js')); 
const NewPhotoRenderer = React.lazy(() => import('./NewPhotoRenderer.js'));

// v18
import OldPhotoRenderer from './OldPhotoRenderer.client.js'; 
import NewPhotoRenderer from './NewPhotoRenderer.client.js';

 

기타: New Hooks

useId

  • 난수 ID를 생성하는 Hook 입니다.
  • 클라이언트와 서버간의 hydration의 불일치를 피하면서 유니크 아이디를 생성 기능을 제공
  • 공식문서

useSyncExternalStore

  • 동시성 기능을 사용할 때 전역 상태 관리 라이브러리의 상태가 업데이트 되지 않을 경우 강제로 업데이트를 발생시키는 Hook입니다.
  • *기존의 useMutableSource hook에서 변경되었습니다.
  • 공식문서

useDeferredValue

  • 트리에서 급하지 않은 부분의 재랜더링을 지연할 수 있는 기능을 지원하는 Hook 입니다.
  • 디바운스와 비슷하지만 고정된 지연시간이 없고 렌더링이 반영되는 시점에 지연 렌더링을 시도합니다.
  • 공식문서

useInsertionEffect

  • CSS-in-JS 라이브러리를 활용할 때 스타일 삽입 성능 문제를 해결할 수 있는 Hook 입니다.
  • Dom이 한번 mutate된 이후 실행되지만 layout effect가 발생하기 전 새 레이아웃을 한번 읽을 수 있기 때문에 사전에 계산할 수 있는 기회가 주어집니다.
  • 기존 useLayoutEffect와 비슷하지만 다른점은 DOM 노드에 대한 참조에 접근할 수 있게 됩니다.
  • 공식문서

 

 

 

 

 

 

 

 

 

 

[참고자료]

React-18-주요-변경점

Suspense SSR Architecture in React 18

저작자표시 비영리 변경금지 (새창열림)

'React' 카테고리의 다른 글

useState vs useRef vs 일반 JS 초기화  (0) 2024.04.15
React DOM Element, ComponentElement  (0) 2024.04.15
검색 기능 구현 시 고려사항(API 호출 시점, debouncing)  (0) 2024.04.15
Redux → SWR(2): SWR로 Redux 대체 가능한가?  (0) 2024.04.13
Redux → SWR(1): Redux의 한계  (1) 2024.04.13
'React' 카테고리의 다른 글
  • useState vs useRef vs 일반 JS 초기화
  • React DOM Element, ComponentElement
  • 검색 기능 구현 시 고려사항(API 호출 시점, debouncing)
  • Redux → SWR(2): SWR로 Redux 대체 가능한가?
URE
URE
Skill: Javascript, ReactJS, Next.js, React Native ... *블로그 이전 작업(24. 04. 11 ~ 24. 04. 15)
  • URE
    Dev++
    URE
  • 전체
    오늘
    어제
    • 분류 전체보기 (51)
      • Browser (6)
      • OS (1)
      • Javascript (14)
      • React (19)
      • Next.js (4)
      • React Native (0)
      • Architecture (1)
      • Network (3)
      • 스크랩 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    IP
    브라우저
    자바스크립트
    리액트
    TCP
    Port
    dataFetching
    react
    원시타입
    react concurrent
    상태관리라이브러리
    참조타입
    URL
    리덕스
    swr
    JS
    javascript
    react18
    리액트 코어
    Redux
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
URE
React 18 주요 변경점
상단으로

티스토리툴바