본문 바로가기
개발/React

React 18 - useDeferredValue를 이용한 Concurrent Mode 확인

by 안뇽! 2023. 8. 3.
반응형

useDeferredValue를 이용한 Concurrent Mode 확인

react 18의 대표 업데이트중 하나는 concurrent mode이다. concurrent mode는 동시성 렌더링인데 실제로 동시는 아니고, 렌더링 우선순위를 정할 수 있는 기능이다. useTransition과 useDeferredValue가 있는데, useDeferredValue를 이용하여 concurrent mode가 어떤것인지 한번 살펴보자.

Concurrent Mode의 도입

React 18에서는 Concurrent Mode를 도입하여 사용자 경험과 성능을 크게 향상시킬 수 있다. Concurrent Mode를 통해 특정 컴포넌트 렌더링이 더 우선순위를 갖고, 사용자와 상호작용하는 동안 더 빠르게 렌더링될 수 있다. 이로 인해 사용자가 더 빠르고 반응적인 웹 애플리케이션을 경험할 수 있다.

 

Concurrent Mode란?

Concurrent Mode는 React 18에서 도입된 새로운 렌더링 모드로, 컴포넌트 렌더링의 우선순위를 조절하여 사용자 경험을 개선하는 기능이다. 이전의 동기식 렌더링 모드와 달리 Concurrent Mode는 렌더링 작업을 여러 우선순위로 나누어 처리하므로, 사용자와의 상호작용에 더 직접적인 영향을 미치지 않고도 더 나은 성능을 제공한다.

 

import React, { useState, useEffect, useDeferredValue, useMemo } from 'react';
import styled from 'styled-components';
const TestWrapper = styled.div`
  display: flex;
  flex-wrap: wrap;
`;

const TestChild = styled.div<{ color: string }>`
  width: 100px;
  height: 100px;
  background-color: ${({ color }) => color};
`;
const DeferredValue2 = () => {
  const [count, setCount] = useState(0);
  const deferredCount = useDeferredValue(count);

  const boxes = useMemo(() => {
    //랜덤색깔 매핑해서 배열로 뿌림
    // 비동기적인 작업이라고 가정한다. (예: 서버에 데이터 전송)
    // Concurrent Mode를 사용하면 사용자와의 상호작용 중에도
    // 렌더링이 중단되지 않고 더 빠르게 반영될 수 있다.
    const x = Math.floor(Math.random() * 256);
    const y = Math.floor(Math.random() * 256);
    const z = Math.floor(Math.random() * 256);
    const backgroundColor = 'rgb(' + x + ',' + y + ',' + z + ')';
    return (
      <TestWrapper>
        {new Array(20000).fill(null).map((_, i) => {
          const x = Math.floor(Math.random() * 256);
          const y = Math.floor(Math.random() * 256);
          const z = Math.floor(Math.random() * 256);
          const backgroundColor = 'rgb(' + x + ',' + y + ',' + z + ')';
          return (
            <div key={i} style={{ width: 100, height: 100, backgroundColor }} />
          );
        })}

        <TestChild color={backgroundColor} />
      </TestWrapper>
    );
  }, [deferredCount]);

  const handleIncrement = () => {
    setCount((prevCount) => prevCount + 1);
  };

  return (
    <div>
      <h2>Concurrent Mode를 활용한 카운터</h2>
      <p>현재 count: {count}</p>
      <p>현재 deferredCount: {deferredCount}</p>
      <button onClick={handleIncrement}>증가</button>
      {boxes}
    </div>
  );
};

export default DeferredValue2;

 

useDeferredValue는 Concurrent Mode를 사용하기 위해 React 18에서 도입된 기능이다. useDeferredValue는 특정 값의 업데이트 우선순위를 낮추는 기능이다. deferredValue는 업데이트가 지연되고, 이를 통해 count 상태의 변경이 사용자와의 상호작용에 미치는 영향을 최소화하면서 비동기 작업의 성능을 향상시킬 수 있다.

useDeferredValue를 이용한 성능 비교

 

boxes는 컴포넌트의 의존성에 일반 state인 count를 걸어놓았다.

  const [count, setCount] = useState(0);
  const deferredCount = useDeferredValue(count);

  const boxes = useMemo(() => {
    //랜덤색깔 매핑해서 배열로 뿌림
    // 비동기적인 작업이라고 가정한다. (예: 서버에 데이터 전송)
    // Concurrent Mode를 사용하면 사용자와의 상호작용 중에도
    // 렌더링이 중단되지 않고 더 빠르게 반영될 수 있다.
    const x = Math.floor(Math.random() * 256);
    const y = Math.floor(Math.random() * 256);
    const z = Math.floor(Math.random() * 256);
    const backgroundColor = 'rgb(' + x + ',' + y + ',' + z + ')';
    return (
      <TestWrapper>
        {new Array(20000).fill(null).map((_, i) => {
          const x = Math.floor(Math.random() * 256);
          const y = Math.floor(Math.random() * 256);
          const z = Math.floor(Math.random() * 256);
          const backgroundColor = 'rgb(' + x + ',' + y + ',' + z + ')';
          return (
            <div key={i} style={{ width: 100, height: 100, backgroundColor }} />
          );
        })}

        <TestChild color={backgroundColor} />
      </TestWrapper>
    );
     // 의존성 배열에 count를 넣는다.    
  }, [count]);

count에 의한 화면 업데이트는 렉이 걸린다.

이번엔 boxes의 의존성에 deferredCount를 걸어놓았다.

const [count, setCount] = useState(0);
  const deferredCount = useDeferredValue(count);

  const boxes = useMemo(() => {
    //랜덤색깔 매핑해서 배열로 뿌림
    // 비동기적인 작업이라고 가정한다. (예: 서버에 데이터 전송)
    // Concurrent Mode를 사용하면 사용자와의 상호작용 중에도
    // 렌더링이 중단되지 않고 더 빠르게 반영될 수 있다.
    const x = Math.floor(Math.random() * 256);
    const y = Math.floor(Math.random() * 256);
    const z = Math.floor(Math.random() * 256);
    const backgroundColor = 'rgb(' + x + ',' + y + ',' + z + ')';
    return (
      <TestWrapper>
        {new Array(20000).fill(null).map((_, i) => {
          const x = Math.floor(Math.random() * 256);
          const y = Math.floor(Math.random() * 256);
          const z = Math.floor(Math.random() * 256);
          const backgroundColor = 'rgb(' + x + ',' + y + ',' + z + ')';
          return (
            <div key={i} style={{ width: 100, height: 100, backgroundColor }} />
          );
        })}

        <TestChild color={backgroundColor} />
      </TestWrapper>
    );
  }, [deferredCount]);

deferredCount가 더 느리게 업데이트 된다.

1. 화면에 렉이 걸리지 않고 매끄럽게 변화한다.

2.클릭을 30번 빠르게 하면 count보다 deferredCount가 느리게 증가한다.

 

  const deferredCount = useDeferredValue(count);

 

deferredCount 업데이트가 지연되도록 설정하였기 때문에 다른 중요한 업데이트들의 우선순위를 높힐 수 있다.

 

Concurrent Mode를 활용하면 컴포넌트 렌더링이 사용자와의 상호작용에 미치는 영향을 최소화한다. 이로 인해 더 빠른 반응성과 원활한 사용자 경험을 제공할 수 있다. 위 예시 코드에서는 카운터의 증가 버튼을 누를 때마다 렌더링 작업이 비동기적으로 처리되어 더 빠른 반영이 이루어진다.

 

 

반응형