Front-End/React

React v18

Voyage_dev 2024. 7. 31. 14:01

React 18 버전에 대한 소개

✔️ React 18 버전에 대해 알아보자

→ 24년 4월 25일 React 19 베타 버전이 출시되었지만 아직 정식으로는 출시되지 않았기 때문에 지금은 18버전에 대해 알아보고 추후에 19버전에 대해 알아보자!

 

React 18 공식 문서

React v18.0 – React

 

React v18.0 – React

The library for web and native user interfaces

react.dev

 

  • 가장 중요한 내용은 동시성을 지원한다 즉, UI에 여러가지 버전이 한꺼번에 존재를 하는데 이러한 버전들을 동시에 보여주는 것을 동시에 보여주는 것을 가능하게 하는 것이 동시성이다
  • 이러한 동시성은 외부에서는 잘 보여지지 않지만 리액트 팀에서 내부적으로 구현을 할 때 이 개념을 많이 사용을 했고 예를 들면 우선순위 큐라든지 아니면 멀티플 버퍼링 같은 개념을 구현을 하는데 사용을 한 것이다
  • 동시성에서 가장 중요한 특징은 이 렌더링이 간섭 가능하다는 점이다. 이전에는 업데이트를 할 때 한 번에 간섭할 수 없고 동기적인 트랜잭션을 통해 이루어진 것을 알 수가 있는데 이러한 방식의 문제점은 한 번 업데이트 렌더링이 일어났을 때, 어떠한 것들도 간섭을 할 수가 없어서 유저는 그 결과를 볼 때까지 계속해서 기다려야만 했다.
  • 하지만 동시성이 React 18버전에서 나온 이후에 이러한 우리가 단일에 간섭할 수 없고 동기적인 방식의 트랜잭션을 사용하는 원리가 확 바뀐 것을 알 수가 있다. React는 업데이트를 시작을 하고 중간에 멈추기도 하고 그리고 나서 다시 시작하기도 하는고 때로는 진행 중인 렌더링을 통째로 버리기도 한다. React는 이렇게 렌더링이 간섭되어도 UI에서 간섭되는 것들이 보여지지 않고 지속적으로 어떤 화면이 보여질 수 있도록 원칙을 보장한다. 이게 가능한 이유는 DOM을 조작하는 연산을 가장 마지막에 하고 모든 트리가 연산이 맞춰진 후에 조작을 하는 방식으로 진행이 되기 때문이다.

18버전에서 추가된 훅 (가장 중요한 3가지)

☑️ useId

  • 컴포넌트별로 유니크한 값을 생성하는 훅
  • 만약에 SSR을 통해 컴포넌트에 유니크한 값을 부여해야 한다고 했을 때 어떻게 할 것인가?
export default function UniqueIdComponent() {
	return <div>{Math.random()}</div> 
	// 서버 사이드에서 렌더링이 될 때 난수가 한 번 생성이 되는데, 클라이언트에서 하이드레이션이 될 때 
	// 값이 바뀌기 때문에 두 번의 연산에서 다른 값이 나오게 된다 => 에러
}
  • 하이드레이션까지 고려하여 유니크한 값을 부여해야 하는데 굉장히 까다로운 작업
  • 이 때 useId 훅을 사용하면 클라이언트와 서버의 불일치를 피해서 컴포넌트 내부의 고유한 값을 생성할 수 있다
  • https://react.dev/reference/react/useId
 

useId – React

The library for web and native user interfaces

react.dev

 

import { useId } from 'react';

function PasswordField() {
  const passwordHintId = useId();
  return (
    <>
      <label>
        Password:
        <input
          type="password"
          aria-describedby={passwordHintId}
        />
      </label>
      <p id={passwordHintId}>
        The password should contain at least 18 characters
      </p>
    </>
  );
}

export default function App() {
  return (
    <>
      <h2>Choose password</h2>
      <PasswordField />
      <h2>Confirm password</h2>
      <PasswordField />
    </>
  );
}

https://react.dev/reference/react/useId#usage

예를 들어 어떤 비밀번호를 재설정하는 컴포넌트를 만든다고 했을 때 위 코드와 같이 두 개의 컴포넌트는 거의 대부분 요소들이 비슷하기 때문에 하나의 패스워드 필드라는 값으로 만들어서 사용하는 것이 일반적으로 생각할 수 있는 방법이다.

 

하지만, 위 두 개의 컴포넌트는 각각 다른 컴포넌트이기 때문에 구분을 해줘야 한다. 그래서 이 안에서 이 구분해 줄 수 있는 값을 passwordHintId라는 이름으로 useId로 부터 고유한 아이디 값을 받을 수가 있다.

 

그리고 이 아이디 값을 이렇게 HTML에 적용을 해보면

https://react.dev/reference/react/useId#usage

이렇게 id 값이 R1, R3 서로 다른 id 값을 가진 것을 확인해 줄 수 있다.

☑️ useTransition

  • UI 변경을 가로막지 않고 상태를 업데이트 할 수 있는 리액트 훅
  • 이 훅을 통해 긴급하지 않은 상태 업데이트를 미룰 수 있고 무거운 렌더링 작업이 있는 경우 효율적
  • 리액트 동시성 관련된 기능 중 하나이다
    • 느린 렌더링 과정에서 로딩 화면을 보여주거나 지금 진행 중인 렌더링을 버리고 새로운 상태값으로 다시 렌더링을 하는 작업도 가능하다
  • https://react.dev/reference/react/useTransition
 

useTransition – React

The library for web and native user interfaces

react.dev

const [isPending, startTransition] = useTransition()
  • 훅을 통해서 호출할 수 있고 isPending을 첫 번째 값으로 startTransition 두 번째 값으로 받는다.
function TabContainer() {
  const [isPending, startTransition] = useTransition();
  const [tab, setTab] = useState('about');

  function selectTab(nextTab) {
    startTransition(() => {
      setTab(nextTab);
    });
  }
  // ...
}
  • isPending과 startTransition을 useTransition로 첫 번재로 먼저 받아주고 우리가 사용하는 컴포넌트 안에서 관리되는 상태 값을 startTransition을 통해서 상태를 조절해 줄 수 있다
  • startTransition안에 콜백 함수로 이 상태를 업데이트 해주는 로직을 넣어주게 되면 상태 업데이트가 바로바로 되는 게 아니라 UI 변경을 블록킹하지 않는 선에서 약간 지연시켜서 처리를 해 줄 수가 있게 된다

사용시 주의할 점

  • startTransition 내부는 반드시 setState 같은 상태 업데이트 하는 함수 작업만 가능하다. 만약 props나 사용자 정의 훅에서 반환하는 값을 사용하고 싶다면, useDeferredValue를 써야한다
  • startTransition으로 넘겨주는 상태 업데이트는 다른 동기 업데이트로 인해 지연될 수 있다
  • startTranstiion으로 넘겨주는 함수는 반드시 동기 함수여야 한다. 만약 이 안에 비동기 함수(setTimeout)같은 함수를 넣으면 제대로 동작하지 않는다

☑️ useDeferredValue

  • 리액트 컴포넌트 트리에서 리렌더링이 급하지 않은 부분을 지연할 수 있게 도와주는 훅
  • 디바운스랑 비슷하지만 차이점 존재 : 고정된 지연 시간이 없이 첫 번째 렌더링이 완료된 후 useDeferredValue로 지연된 렌더링을 수행한다
  • useTransition과의 차이점
    • useTransition : state 값을 업데이트 하는 함수를 감싸서 사용
    • useDeferredValue : state 값 자체만을 감싸서 사용
  • https://react.dev/reference/react/useDeferredValue
 

useDeferredValue – React

The library for web and native user interfaces

react.dev

 

const deferredValue = useDeferredValue(value)
  • 어떤 값을 useDeferredValue 처리하고 싶을 때 훅의 첫 번째 인자로 넣어주고 선언해 줄 수 있다
import { useState, useDeferredValue } from 'react';

function SearchPage() {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  // ...
}
  • query가 계속해서 바뀌는 경우 즉, 검색 같은 경우에 키워드에 따라 쿼리가 계속 바뀔 수가 있는데 그럴 때마다 이 쿼리로 인해서 화면의 업데이트가 지연이 되거나 방해가 될 때 useDeferredValue로 처리를 해줄 수가 있다

이 외에도 리액트 18 번전에서 추가가 됐는데 필요한 훅들이 있으면 공식 문서를 통해서 알아보자