Post

[React] 느린 컴포넌트 성능 향상 useTransition, useDeferredValue

[React] 느린 컴포넌트 성능 향상 useTransition, useDeferredValue

react 18 버전에서 새롭게 추가된 hook이 있다.

useTransition

useTransition을 사용하면 동작이 느린 컴포넌트들을 혁신적으로 빠르게 동작시킬 수가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// App.js
import { useState } from "react";

function App(){
  let [name, setName] = useState('');
  let arr = new Array(10000).fill(0);	// 0이 10000개 담긴 arr

  return (
    <div className="App">
      <input onChange={(e)=>{ setName(e.target.value) }} />
      {
        arr.map(()=>{
          return <div>{name}</div>
        })
      }
    </div>
  )
}

input에 유저가 글을 입력하게 되면 그 값을 name 이라는 state에 저장한 후 arr의 갯수(10000개)만큼 뿌려주는 코드다.
유저가 타이핑을 입력할때마다 10000개의 div박스를 생성하기 때문에 매우 느리다.

성능저하의 원인이 되는 부분을 startTransition으로 감싼다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// App.js
import { useState, useTransition } from "react";

let arr = new Array(10000).fill(0);	// 0이 10000개 담긴 arr

function App(){
  let [name, setName] = useState('');
  let [isPending, startTransition] = useTransition()

  return (
    <div className="App">
      <input onChange={(e)=>{
        startTransition(()=>{
          setName(e.target.value)
        })
      }} />
      {
        isPending
        ? '로딩중...'
        : arr.map(()=>{
          return <div>{name}</div>
        })
      }
    </div>
  )
}

브라우저는 한번에 한가지 작업밖에 못하는데,
위의 같은 경우에는 input에 글자를 보여주기, div * 10000 만들기 2가지 일을 해야 하기때문에 버벅거리게 된다.
그런데 startTransition 함수로 감싸게 되면 startTransition안의 코드를 늦게 실행한다.

startTransition으로 실행 시점을 조절함으로써 성능 향상의 효과를 기대할 수 있다.
startTransition === 늦게처리

isPending은 startTransition이 처리중일 때 true를 반환한다.

useDeferredValue

useDeferredValue를 사용해도 느린 컴포넌트의 성능을 향상시킬 수있다.
useDeferredValue() 함수 안에 넣은 state는 늦게 처리해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// App.js
import { useState, useTransition, useDeferredValue } from "react";

let arr = new Array(10000).fill(0);	// 0이 10000개 담긴 arr

function App(){
  let [name, setName] = useState('');
  let [isPending, startTransition] = useTransition()
  let state = useDeferredValue(name)

  return (
    <div className="App">
      <input onChange={(e)=>{
        startTransition(()=>{
          setName(e.target.value)
        })
      }} />
      {
        isPending
        ? '로딩중...'
        : arr.map(()=>{
          return <div>{state}</div>
        })
      }
    </div>
  )
}
This post is licensed under CC BY 4.0 by the author.