[React] React 18에서 추가된 hook

김재훈·2023년 4월 17일
0

useId

useId hook은 React 18에 새로 추가된 hook으로 유니크한 id를 만들어준다. 다음과 같은 상황에서 사용한다.

  • 입력이 있는 label과 같이 두 개의 HTML 요소를 함께 연결할 때
  • 매번 고유 ID를 생성해야 하는 곳
  • 동일한 생성 ID를 여러 번 사용할때 접두사 또는 접미사로 사용

그리고 list에서 key로는 사용하면 안 되고 변경해서는 안 되는 값에는 사용하면 안 된다.

import {useId} from 'react';

const id = useId();

<label htmlFor={`${id}-firstName`}>
  이름
  <input id={`${id}-firstName`} />
</label>

useTransition

useTransition 훅을 사용하면 상태 변화의 우선순위를 지정할 수 있다. useTransition 훅은 2개의 배열[isPending, startTransition]을 반환하는데 isPending은 작업이 지연되고 있음을 알리는 boolean이고 startTransition은 낮은 우선순위로 실행할 함수를 인자로 받는다.

import {useTransition, useState} from 'react';

function App() {
  const [isPending, startTransition] = useTransition();
  const [count, setCount] = useTate(0);
  
  function handleClick() {
    startTransition(() => {
      setCount(c => c + 1);
    });
  }
  
  return (
    <div>
      {isPending && <Spinner />}
      <button onClick={handleClick}>{count}</button>
    </div>
  );
}

위 코드는 클릭할 때마다 일어나는 count에 대한 상태 업데이트를 낮은 우선순위로 실행한다. 더 중요한 이벤트가 있는 경우 count의 업데이트를 지연시키고 대신 이전의 값을 보여준다.
isPending을 사용하여 업데이트가 지연되는 동안 스피너를 보여줄 수도 있다.

useDeferredValue

useDeferredValue훅 또한 useTransition훅과 유사하게 낮은 우선순위를 지정할 수 있다. 차이점은 useTransition훅은 함수 실행의 우선순위를 지정하는 반면, useDeferredValue훅은 값의 업데이트 우선순위를 지정한다. 우선순위가 높은 작업을 실행하는 동안 useMemo와 유사하게 이전 값을 계속 들고 있으면서 업데이트를 지연시킨다.

이 훅은 useMemo와 함께 사용하면 더 효과가 좋다. 종속된 값들을 memoization 시키면 불필요한 리렌더링(re-render)을 막으면서 하위 컴포넌트나 상태의 업데이트를 지연시킬 수 있다.

아래는 검색 자동완성을 처리하는 코드다. 사용자 입력 query의 업데이트에 대해 추천 검색어인 suggestions를 띄워 준다. 추천 검색어의 업데이트는 우선순위가 높은 작업이 없을 때만 실행된다.

function Typeahead() {
  const query = useSearchQuery('');
  const deferredQuery = useDeferredValue(query);

  // Memoizing tells React to only re-render when deferredQuery changes,
  // not when query changes.
  const suggestions = useMemo(() =>
    <SearchSuggestions query={deferredQuery} />,
    [deferredQuery]
  );

  return (
    <>
      <SearchInput query={query} />
      <Suspense fallback="Loading results...">
        {suggestions}
      </Suspense>
    </>
  );
}

useInsertionEffect

useInsertionEffectuseLayoutEffect가 동작하기 전에 스타일을 먼저 조작하게 해주는 훅으로 CSS-in-JS 라이브러리가 렌더링도중에 스타일을 삽입할 때 발생하는 성능 문제를 해결한다.

useInsertionEffect의 시그니처는 useEffect와 동일하다. 그러나 모든 DOM 조작 전에 동기적으로 실행된다. useLayoutEffect에서 레이아웃을 읽기 전에 <style> 또는 SVG <defs>와 같은 전역 DOM 노드를 삽입하는 데 사용해야 한다. 실제로 이러한 CSS 라이브러리 이외의 다른 용도로 사용되는 것은 아니다.

function useCSS(rule) {
  useInsertionEffect(() => {
    if (!isInserted.has(rule)) {
      isInserted.add(rule);
      document.head.appendChild(getStyleForRule(rule));
    }
  });
  return rule;
}
function App() {
  let className = useCSS(rule);
  return <div className={className} />;
}

참고

profile
김재훈

0개의 댓글