React v18

April 8, 2022 - 3 minute read -
React

React v18 New features 간단 요약

Automatic batching

// Before: only React events were batched.
setTimeout(() => {
    setCount(c => c + 1);
    setFlag(f => !f);
// React will render twice, once for each state update (no batching)
}, 1000);

// After: updates inside of timeouts, promises,
// native event handlers or any other event are batched.
setTimeout(() => {
    setCount(c => c + 1);
    setFlag(f => !f);
// React will only re-render once at the end (that's batching!)
}, 1000);

리액트 내부의 라이프싸이클이나, 리엑트 이벤트 핸들러 안에서 발생되는 state 변경 발생하는 경우만 모두 모아서 일괄 처리되고 네이티브 이벤트 핸들러, 외부 모듈이나 비동기, 프로미스 내에서는 일괄 처리를 지원하지 않았다.
이는 한 번의 이벤트에 여러번의 렌더링이 발생할 수 있어 비효율적이었다.
보기만해도 쓰기 싫게 생긴 함수(ReactDOM.unstable_batchedUpdates) 로 일괄 처리를 임시 지원하고 있었는데, 자동으로 상태 변경을 일괄 처리하도록 변경되었다.




Transitions

import {startTransition} from 'react';

// Urgent: Show what was typed
setInputValue(input);

// Mark any state updates inside as transitions
startTransition(() => {
// Transition: Show the results
    setSearchQuery(input);
});

유저 경험을 중심으로 봤을 때, 바로 처리되어야 하는 UI와 조금의 지연이 허용되는 UI가 있다.
가령, 클릭, 타이핑 등의 액션은 바로 반응이 보여져야 한다. 하지만 타이핑을 통해 리스트로 된 결과를 얻는다던가, 체크박스로 필터된 아이템들을 보여주는 등의 액션은 어느정도 지연이 허용된다.

Urgent updates reflect direct interaction, like typing, clicking, pressing, and so on.
Transition updates transition the UI from one view to another.

이전에는 UI에 대한 우선순위 구분이 없어 급하게 처리되어야할 UI들이 블락당하는 경우가 있었고, 비동기로 처리하거나 debounce, throttle을 활용하는 등 우회하는 방법을 썼다.
React.18에서는 급하게 처리되어야할 UI가 아니라면, 더 급한 UI 렌더링을 우선하게 된다.

Susepnse와 상당히 잘 어울리는데,

    function handleClick() {
        startTransition(() => {
            setTab('comments');
        });
    }

    <Suspense fallback={<Spinner />}>
    	{tab === 'photos' ? <Photos /> : <Comments />}
    </Suspense>

위와 같이 transition 중 suspense가 적용되면, 일단 fallback을 막고 데이터를 다 가져올 때 까지 기존 화면으로 기다린다.
깜빡이는 UI를 방지할 수 있을듯!




SSR & Suspense


SSR 과정은 대략적으로 아래와 같다.
Data Fetching -> HTML response -> JS 다운로드 -> Hydration
여기서 문제였던 부분은, 각각의 과정이 모드 완료되어야 다음 순서로 넘어간다는 것이다.
즉, 만약 특정 컴포넌트에서의 data fetching이 시간이 너무 오래 걸리면 전체 HTML reponse가 지연 되고, 특정 컴포넌트의 JS 파일이 너무 크면 전체 Hydration이 지연되었다.

React.18 에서는 Server side에서의 Susepnse 사용과 Server streaming api 업데이트를 통해, 선택적으로 HTML render, JS load, Hydration을 처리할 수 있게되었다.




New Client and Server Rendering APIs

기존 버전을 계속 사용할 수 있도록 렌더링 관련된 api 추가.

React DOM Client

  • createRoot: React v18 새 기능을 사용하기 위해 ReactDOM.render 대신 사용
  • hydrateRoot:React v18 새 기능을 사용하기 위해 ReactDOM.hydrate 대신 사용

React DOM Server

Suspense를 스트리밍할 수 있도록 지원 (renderToString 대체)

  • renderToPipeableStream: Node environments.
  • renderToReadableStream: 최근 런타임 환경 (Deno and Cloudflare workers..)




Resource

https://github.com/reactwg/react-18/discussions/21 https://github.com/reactwg/react-18/discussions/37 https://github.com/reactjs/rfcs/blob/main/text/0213-suspense-in-react-18.md https://reactjs.org/blog/2022/03/29/react-v18.html https://www.youtube.com/watch?v=pj5N-Khihgc&list=PLNG_1j3cPCaZZ7etkzWA7JfdmKWT0pMsa&index=4