ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • useTransition와 useDeferredValue 알아보기
    Frameworks, Platforms and Libraries/React 2024. 4. 28. 13:59

    React 18버전에서 새로 나온 hooks인 useTransition을 이번에 사용하게 되어 팀 내에서도 공유하고 포스팅도 하게 되었습니다. useTransition와 비슷한 역할을 가진 useDeferredValue도 같이 알아보겠습니다.

     

    useTransition?

    React 공식 홈페이지에서 useTransition 설명은 다음과 같습니다.

    useTransition is a React Hook that lets you update the state without blocking the UI.
    useTransition 은 UI를 차단하지 않고 state를 업데이트할 수 있는 React 훅입니다.

     

    useTransition은 파라미터를 받지 않고 isPending, startTransition 두 개의 값을 반환합니다. isPending은 트랜지션의 지연 상태를 나타내는 boolean 타입의 flag 값이며 startTransition은 state의 변화를 트랜지션으로 나타내는 함수로 파라미터로 콜백 함수를 받으며 전달받은 함수의 우선순위를 낮춰 지연시키는 함수입니다.

      const [isPending, startTransition] = useTransition();

     

     

    해당 내용만 봐선 useTransition의 이해가 쉽게 와닿지 않아 예시를 통해 살펴보겠습니다.

    import { ChangeEvent, useEffect, useState } from 'react';
    
    import './App.css';
    
    function App() {
      const [count, setCount] = useState<number>(0);
      const [countArr, setCountArr] = useState<number[]>([]);
    
      const updateCount = () => {
        const arr = Array(100000)
          .fill(0)
          .map((_, i) => count * i);
        setCountArr(arr);
      };
    
      useEffect(() => {
        updateCount();
      }, [count]);
    
      return (
        <>
          <h1>React Hooks Test</h1>
          <div className="section">
            <input
              type="number"
              value={count}
              onChange={(e: ChangeEvent<HTMLInputElement>) =>
                setCount(Number(e.currentTarget.value))
              }
            />
    
            <div className="box">
              {countArr.map((val, idx) => (
                <span key={idx}>{val}</span>
              ))}
            </div>
          </div>
        </>
      );
    }
    
    export default App;

     

    실제 개발 시 나오지 않을 코드이지만 state의 극단적인 변화를 보이기 위해 작성된 코드입니다. 해당 코드의 결과는 아래와 같습니다.

     

    updateCount의 무거운 로직으로 인해 state의 setting이 늦어지며 이에 따라 UI의 끊김 현상을 살펴볼 수 있습니다.

     

    useTransition을 사용하여 위의 코드를 개선해 보겠습니다.

    import { ChangeEvent, useEffect, useState, useTransition } from 'react';
    
    import './App.css';
    
    function App() {
      const [count, setCount] = useState<number>(0);
      const [countArr, setCountArr] = useState<number[]>([]);
    
      const [isPending, startTransition] = useTransition();
    
      const updateCount = () => {
        startTransition(() => {
          const arr = Array(100000)
            .fill(0)
            .map((_, i) => count * i);
          setCountArr(arr);
        });
      };
    
      useEffect(() => {
        updateCount();
      }, [count]);
    
      return (
        <>
          <h1>React Hooks Test</h1>
          <div className="section">
            <input
              type="number"
              value={count}
              onChange={(e: ChangeEvent<HTMLInputElement>) =>
                setCount(Number(e.currentTarget.value))
              }
            />
            {isPending && <div className="load-box">loading...</div>}
            {!isPending && (
              <div className="box">
                {countArr.map((val, idx) => (
                  <span key={idx}>{val}</span>
                ))}
              </div>
            )}
          </div>
        </>
      );
    }
    
    export default App;

     

    startTransition을 통해 updateCount 실행의 우선순위를 낮추고 이에 따른 트랜지션 상태를 isPending을 통해 판단하여 조건부 렌더링을 걸어두었습니다.

     

    결국 useTransition은 startTransition을 통해 함수 실행의 우선순위를 늦출 수 있으며 이에 따른 지연 상태를 isPending으로 나타냅니다. useTransition을 이용한 UI를 사용자에게 제공 시 더 나은 UX를 가지게 합니다.

     

    useDeferredValue?

    useTransition과 함께 React 18버전에서 나온 useDeferredValue에 대해 알아보겠습니다. 우선 공식 문서에서 설명은 아래와 같습니다.

    useDeferredValue is a React Hook that lets you defer updating a part of the UI.
    useDeferredValue는 UI 일부의 업데이트를 지연시킬 수 있는 React 훅입니다.

     

    useDeferredValue은 파라미터로 모든 타입의 값을 받을 수 있으며 파라미터로 전달받은 값을 그대로 반환하지만 지연된 버전의 값으로 반환합니다.

    const deferredValue = useDeferredValue(value)

     

    위의 내용만 봐선 useDeferredValue의 이해가 쉽지 않지만 useTransition과 비슷한 내용이 많이 보입니다. useDeferredValue도 예시를 통해 살펴보겠습니다.

    import { useDeferredValue, useState } from 'react';
    
    import './App.css';
    
    function App() {
      const [first, setFirst] = useState<number>(0);
      const [second, setSecond] = useState<number>(0);
    
      const deferredValue = useDeferredValue(second);
    
      const updateNumber = () => {
        setFirst((f) => f + 1);
        setSecond((s) => s + 1);
      };
    
      console.log('first', first);
      console.log('second', second);
      console.log('deferredValue', deferredValue);
    
      return (
        <>
          <h1>React Hooks Test</h1>
          <div className="section">
            <button onClick={() => updateNumber()}>button</button>
          </div>
        </>
      );
    }
    
    export default App;

     

    useDeferredValue을 사용하여 선언된 deferredValue의 값의 변화가 다른 state의 변화가 끝난 뒤에 발생되었음을 알 수 있습니다.

     

    결론

    useTransition과 useDeferredValue는 state의 변화에 대한 우선순위를 낮추는 hook이라는 공통점을 가지며 useDeferredValue는 state 값 자체에 우선순위를 낮추지만 useTransition는 state 변화를 일으키는 함수에 우선순위를 낮추는 차이점을 가집니다.

     

    마무리

    React의 버전이 업데이트될수록 다양한 기능이 나오고 있습니다. React의 버전을 업데이트할 때 새로운 기능을 파악하여 적재적소에 맞게 사용해야겠습니다.


    참고 자료

    https://react-ko.dev/reference/react/useTransition

    https://react-ko.dev/reference/react/useDeferredValue

    https://dev.to/sameer1612/react-v18-usetransition-hook-why-3bml

     

Designed by Tistory.