[FE] React 18 정리

KoSH·2024년 2월 29일
post-thumbnail

Automatic Batching, startTransition 과 같은 새로운 API, Suspense 를 지원하는 SSR 등, React 18 의 새로운 기능들을 훑어보자


먼저 React 18의 새로운 기능들을 사용하기 위해서는 createRoot API 를 사용해야한다.

// 이전
import React from 'react';
import ReactDOM from 'react-dom';

// render 사용
ReactDOM.render(
	<App />,
document.getElementById('root')
)

// react 18
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

ReactDOM.createRoot(document.getElementById('root')).render(
    <App />,
)

기존 버전에서는 render 만을 사용해 root 를 생성했는데 React 18 버전에서는 creatRoot 라는 새로운 Root API 를 통해 root 를 생성할 수 있게 되었다.

CRA 대신 Vite를 사용해 프로젝트를 생성한 경우 자동으로 createRoot 를 사용하여 프로젝트가 생성된다!


React 18 의 새로운 주요 기능들

  • Automatic Batching

  • Concurrent Feature

  • New Hooks



Automatic Batching


Automatic Batching 은 여러 상태 업데이트를 통합하여 단일 리렌더링으로 처리하여 리렌더링 성능을 개선한 기능이다.

React 18 이전엔 useState, setState 를 통해 상태를 업데이트하고 업데이트된 결과를 바탕으로 리렌더링을 진행했다. 이때, state 의 개수가 많아지면 그만큼 리렌더링 숫자도 늘어나고, 불필요한 리렌더링의 수도 늘어날 수 있다.


그래서 도입된 기능이 배치처리(batch updating)이다.

배치처리는 여러 상태 업데이트들이 발생해도 상태를 하나로 통합해 리렌더링을 진행하는 방식이다. React 18 이전 버전에서는 이벤트 핸들러와 생명주기 메서드를 사용할 땐 배치처리를 지원하지만 콜백 함수가 포함된 경우 배치처리를 지원하지 않았다.


const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  const handleClick = () => {
    setCount((c) => c + 1); // 아직 리렌더링 안함
    setFlag((f) => !f); // 아직 리렌더링 안함
    // React는 이 함수가 끝나면 리렌더링 (batching)
  };

  return (
    <div>
      <button onClick={handleClick}>Next</button>
      <h1>{count}</h1>
    </div>
  );

React가 자동으로 배칭 하기 떄문에 자동 배칭 기능을 사용하기 위해서 우리가 따로 해야할 작업은 없다. React 18 버전의 createRoot 를 통해, 모든 업데이트들은 어디서 왔는가와 무관하게 자동으로 배칭된다.


이전에는 fetch 등 비동기 함수에서 상태 업데이트 할 때는 배치처리가 안되는 문제가 존재했다.

하지만 createRoot 를 사용하면 비동기 함수 내에서도 배치처리가 제대로 되는 것을 확인할 수 있다.


  const [one, setOne] = useState(0);
  const [two, setTwo] = useState(0);

  const onClick = () => {
    fetch('https://jsonplaceholder.typicode.com/posts/1').then((res) => {
      setOne(one + 1);
      setTwo(two + 1);
    });
  };

  console.log('리렌더링');
  return (
    <>
      <button onClick={onClick}>Fetch</button>
      <h1>{one}</h1>
      <h1>{two}</h1>
    </>
  );

하지만 이벤트 핸들러 내에서 일반적으로 상태 업데이트를 하는 것과 콜백 함수에서 상태 업데이트를 하는 것이 중복되면 리렌더링이 상태의 개수만큼 발생하는 것을 확인할 수 있다.

setOne(one + 1); // 일반 상태 업데이트

    fetch('https://jsonplaceholder.typicode.com/posts/1').then((res) => {
      setTwo(two + 1); // 콜백 함수 내에서 상태 업데이트
    });
  };

  console.log('리렌더링');
  return (
    <>
      <button onClick={onClick}>Fetch</button>
      <h1>{one}</h1>
      <h1>{two}</h1>
    </>
  );

만약 Automatic Batching 을 방지하고자 한다면 react-dom 의 flushSync() 함수를 사용하면 된다.

  const [one, setOne] = useState(0);
  const [two, setTwo] = useState(0);

  const onClick = () => {
    flushSync(() => {
      setOne(one + 1);
    });
    flushSync(() => {
      setTwo(two + 1);
    });
    
    // 단, 하나의 flushSync에 여러개의 상태 업데이트를 넣으면 효과가 없음
    flushSync(() => {
      setOne(one + 1);
      setTwo(two + 1);
    });
  };


Concurrent Feature


Current Mode 는 자바스크립트가 싱글 스레드 기반의 언어이기 때문에 여러 작업을 동시에 처리할 수 없는 문제점을 보안하기 위해 나왔다.

React 또한 JavaScript 기반이기 때문에 동일한 문제점이 발생하였고 Concurrent Mode(동시성)을 통해 이를 해결하고자했다. Concurrent Mode 는 여러 작업을 작은 단위로 나눠 우선순위를 정해 그에 따른 작업을 번갈아 수행하는 것을 말한다. 동시에 수행되는 것은 아니지만 빠르게 전환되기 때문에 동시에 수행되는 것처럼 보여 UX 를 향상시킨다.

이러한 배경에서 탄생한 Concurrent Feature 은 Concurrent Mode 에서 용어가 바뀐 것으로 이번 React 18 버전에서 중요한 기능이다. 동시성을 효율적으로 진행할 수 있는 기능인 SuspenseTransitions 를 지원한다.



Suspense

Suspense 는 사용자에게 보여주고 싶은 컴포넌트를 먼저 렌더링 할 수 있게 하는 기능이다.


<Suspense fallback={<Spinner />}>
	<Comments />
</Suspense>

Suspense 로 렌더링을 원하는 컴포넌트를 감싸주면 해당 컴포넌트가 렌더링 되기 전까지 fallback 안의 컴포넌트를 사용자에게 보여준다.



Transition

Transition 은 setState(상태 업데이트)의 우선순위를 구분한다. Urgent updates 는 입력, 클릭, 누르기와 같은 사용자가 직접적인 상호 작용을 하는 기능을 말하고, Transtition updates(non-urgent)는 UI 전환과 같은 기능을 말한다.


const [isPending, startTransition] = useTransition();
  const [one, setOne] = useState(0);
  const [two, setTwo] = useState(0);

  const onClick = () => {
    setOne(one + 1); // 긴급 업데이트

    startTransition(() => {
      setTwo(two + 1); // 전환 업데이트로 setOne 보다 우선순위가 낮음
    });
  };
  return (
    <>
      <button onClick={onClick}>btn1</button>
      <button disabled={isPending}>btn2</button>
    </>
  );

isPending 의 값이 true 일 경우 startTransition 내분에 있는 setTow가 우선순위에서 밀린다. setOne의 상태 업데이트 진행시 isPending 의 값은 true 이다. setOne 의 상태 업데이트가 완료되면 isPending 의 값이 false 가 되며 setTwo 의 상태 업데이트를 진행한다.



새로운 Hooks


useId()

서버와 클라이언트에서 사용될 고유 ID 를 생성한다.

  • id 를 하나만 전달할 때
function CreateID(){
	const id = useId();

	return <input id={id} type='text' />;
}

  • id를 두개 이상 전달할 땐 접미사 추가하여 아이디 구분
function CreateID(){
	const id = useId();

	return (
		<input id={id + '-firstID'} type='text' />
		<input id={id + '-secondID'} type='text' />
	)
}


useDefferdValue()

트리에서 긴급하지 않은 부분의 리렌더링을 연기하는 기능 제공
고정된 지연 시간이 없고 긴급한 작업이 완료된 후 즉시 실행하여 사용자의 입력을 차단하지 않는다.


import { useDeferredValue, useState } from 'react';

const SlowUI = () => {
  <>
    {Array(50000)
      .fill(1)
      .map((_, index) => {
        <span key={index}>{10000}</span>;
      })}
  </>;
};

function App() {
  const [value, setValue] = useState(0);
  const deferredValue = useDeferredValue(value); // 긴급하지 않은 값

  const handleClick = (e) => {
    setValue(e.target.value);
  };
  return (
    <>
      <input onChange={handleClick} />
      <div>DeferredValue: {deferredValue}</div>
      <div>
        <SlowUI />
      </div>
    </>
  );
}

export default App;

useTransition 과 같은 역할이라고 착각할 수 있지만, useTransition 은 함수 실행의 우선순위, useDeferredValue 는 값의 업데이트의 우선순위를 지정해준다고 생각하면 된다.



마치며...


React 18 전에도 배치처리가 가능하긴 했다. 하지만 콜백 함수 내에서 배치처리가 안되는 문제점이 있었다. React 18 버전 업데이트를 통해 Automatic Batching 이 가능해졌고, Concurrent Mode 를 통해 기존 사용하던 DebounceThrottle 을 대체할 수 있게 되었고, Suspence 를 통해 로딩이 오래걸리는 컴포넌트를 렌더링 할 때 fallback 을 통해 로딩 화면으로 대체할 수

React 18 전에도 배치처리가 가능하긴 했다. 하지만 콜백 함수 내에서 배치처리가 안되는 문제점이 있었다. React 18 버전 업데이트를 통해 Automatic Batching 이 가능해졌고, Concurrent Mode 를 통해 기존 사용하던 DebounceThrottle 을 대체할 수 있게 되었고, Suspence 를 통해 로딩이 오래걸리는 컴포넌트를 렌더링 할 때 fallback 을 통해 로딩 화면으로 대체할 수 있기 때문에 사용자 경험을 향상시킬 수 있을 것이다.

전체적으로 React 18 업데이트는 사용자 경험을 향상 시키는 것이 중점으로 보인다.

profile
성장형 괴물

0개의 댓글