๐ช ๋์์ฑ ๋ ๋๋ง?
๋ฆฌ์กํธ 18 ๋ฒ์ ผ์ด ๋ฑ์ฅํ๋ฉด์, ๋์์ฑ ๊ธฐ๋ฅ์ ์ง์ํ๋ ์ฌ๋ฌ ํ ๋ค์ด ๋์๋ค.
๋ฆฌ์กํธ ๊ณต์๋ฌธ์์์๋ ๋ค์๊ณผ ๊ฐ์ด ๋งํ๋ค.
React 18 adds the long-awaited concurrent renderer and updates to Suspense without any major breaking changes. Apps can upgrade to React 18 and begin gradually adopting concurrent features with the amount of effort on par with any other major release.
This means there is no concurrent mode, only concurrent features.
React 18์ ์ค๋ซ๋์ ๊ธฐ๋ค๋ ค์จ ๋์ renderer๋ฅผ ์ถ๊ฐํ๊ณ Suspense๋ฅผ ํฐ ๋ณ๊ฒฝ ์์ด ์ ๋ฐ์ดํธํ๋ค. ์ฑ์ React 18๋ก ์ ๊ทธ๋ ์ด๋ํ์ฌ ๋ค๋ฅธ ์ฃผ์ ์ถ์์ ๋๋ฑํ ์์ค์ ๋ ธ๋ ฅ์ผ๋ก ๋์ ๊ธฐ๋ฅ์ ์ ์ง์ ์ผ๋ก ๋์ ํ ์ ์๊ฒ ๋์๋ค. ์ด๋ ๋์ ๋ชจ๋๊ฐ ์๊ณ ๋์ ๊ธฐ๋ฅ๋ง ์์์ ์๋ฏธํ๋ค.
์ฑ์ ์ ์ฒด๋ฅผ ๋์์ฑ ๋ชจ๋๋ก ๊ฒฐ์ ํ๊ณ ๊ฐ๋ฐ์ ํด๊ฐ๋ ๊ฒ์ด ์๋ ๋ฆฌ์กํธ๊ฐ ์ ๊ณตํด์ฃผ๋ ๋์์ฑ ๊ธฐ๋ฅ์ ๊ฐ์ง๋ API๋ค ์ฆ, useTransition
, useDeferredValue
ํ
์ ์ฌ์ฉํด์ ์ฑ์ ๋ถ๋ถ์ ์ผ๋ก ๋์์ฑ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๊ฒ ๋์๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
์กฐ๊ธ ๋ง ๋ ์์ธํ๊ฒ ๋ค์ด๊ฐ ๋ณด์๋ฉด, ๋ฆฌ์กํธ 18 ๋ฒ์ ผ๋ถํฐ createRoot
ํจ์๋ฅผ ํตํด์ ์ ์ฒด ์ปดํฌ๋ํธ ํธ๋ฆฌ๋ฅผ ๋ง๋ค๊ฒ ๋๋ฉด ๋ด๋ถ์ ์ผ๋ก concurrent mode ๊ฐ ์คํ๋๋ค. ํ์ง๋ง concurrent mode ๊ฐ ์คํ๋๋ค๊ณ ํด์, ๋ฌด์กฐ๊ฑด ๋ชจ๋ ๋ ๋๋ง์ ๋์์ฑ์ด ์ ์ฉ๋๋ ๊ฒ์ด ์๋๋ผ concurrent features ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์๋ง ๋ถ๋ถ์ ์ผ๋ก ๋์์ฑ ๋ ๋๋ง์ด ์ ์ฉ๋๋ค๋ ๊ฒ์ด๋ค.
(concurrent features ๋ useTransition
, useDeferredValue
ํ
์ด๋ Suspense
, streaming SSR
๋ฑ์ ๋งํ๋ค.)
๋ฆฌ์กํธ๊ฐ ๋งํ๋ ๋์์ฑ์ ๋ํด์ ์์๋ณด๊ธฐ ์ , ์ปดํจํฐ ๊ณผํ์์ ๋งํ๋ ๋์์ฑ์ ๋ณ๋ ฌ์ฑ๊ณผ ๋น๊ตํด ๋ณด๋ฉด์ ์์๋ณด์.
concurrency(๋์์ฑ)
์ปดํจํฐ ๊ณผํ์์ ๋์์ฑ์ด๋, ๋
๋ฆฝ์ ์ผ๋ก ์คํ๋๋ ํ๋ก์ธ์ค๋ค์ ์กฐํฉ์ ๋งํ๋ค.
๋ฐ๋ฉด, ๋์์ฑ๊ณผ ํท๊ฐ๋ฆฌ๊ธฐ ์ฌ์ด ๊ฐ๋
์ธ ๋ณ๋ ฌ์ฑ์ ์ฐ๊ด๋ ๋ณต์์ ์ฐ์ฐ๋ค์ ๋์์ ์คํํ๋ ๊ฒ์ด๋ค.
๋์์ฑ์ ์ฌ๋ฌ ์ผ์ ํ๊บผ๋ฒ์ ๋ค๋ฃจ๋ ๋ฌธ์ ์ ๊ดํ ๊ฒ์ด๊ณ , ๋ณ๋ ฌ์ฑ์ ์ฌ๋ฌ ์ผ์ ํ๊บผ๋ฒ์ ์คํํ๋ ๋ฐฉ๋ฒ์ ๊ดํ ๊ฒ์ด๋ค.
๋์๊ด ์ฌ์ ์์๋ฅผ ํตํด์ ๋์์ฑ๊ณผ ๋ณ๋ ฌ์ฑ์ ์ข ๋ ์ดํดํด๋ณด์. ๐
- ๋์์ฑ
๋์์ฑ์, ๋์๊ด ์ฌ์๊ฐ ์ฑ ์ ์ ๋ฆฌํ๊ณ ์์๋๋ฐ ๊ผฌ๋ง ์์ด๊ฐ ์ด๋ค ์ฑ ์ ์์น๋ฅผ ์ง๋ฌธํ๋ ์ํฉ์ ๋ ์ฌ๋ ค๋ณด๋ฉด ์กฐ๊ธ ๋ ์ฝ๊ฒ ์ดํดํ ์ ์๋ค.
์ฌ์๋ ์ฑ
์ ์ ๋ฆฌํ๊ณ ์๋ค๊ฐ(task 1
), ๊ผฌ๋ง ์์ด์ ์ง๋ฌธ์ ๋ต์ ํด์ค์ผ ํ๋ค. (task 2
)
์ฆ, ๋์๊ด ์ฌ์๋ ์ฑ ์ ์ ๋ฆฌํ๋ ๋ ผ๋ฆฌ์ ํ๋ฆ๊ณผ ์ง๋ฌธ์ ๋ต์ ํด์ฃผ๋ ๋ ผ๋ฆฌ์ ํ๋ฆ์ ๋ ๋ค ๊ฐ์ง๊ฒ ๋๋ฉฐ ์ฌ์ ํ ๋ช ์ด ๋ ๊ฐ์ง ๋ ผ๋ฆฌ์ ํ๋ฆ์ ๋์์ ์คํํ๋ ๊ฒ ์ฒ๋ผ ๋ณด์ธ๋ค.
- ๋ณ๋ ฌ์ฑ
๋ฐ๋ฉด, ๋ณ๋ ฌ์ฑ์ ๋์๊ด ์ฌ์๊ฐ ๋ ๋ช
์ธ ๊ฒฝ์ฐ๋ฅผ ๋ ์ฌ๋ ค๋ณด๋ฉด ์ฝ๊ฒ ์ดํดํ ์ ์๋ค. ํ ๋ช
์ ์ฑ
์ ์ ๋ฆฌํ๋ฉฐ(task 1
), ๋ค๋ฅธ ํ ๋ช
์ด ๊ผฌ๋ง ์์ด์ ์ง๋ฌธ์ ๋ต์ ํด์ค๋ค. (task 2
)
๊ฐ ์ฌ์๋ค์ ํ๋์ ๋
ผ๋ฆฌ์ ํ๋ฆ์ ๊ฐ์ง๋ฉฐ, ํ ๋ช
์ฉ ์ค์ค๋ก๊ฐ ์ํํด์ผ ํ๋ ๋
ผ๋ฆฌ์ ํ๋ฆ์ ๋
๋ฆฝ์ ์ผ๋ก ์ํํ๋ค.
๋ค์ ์ด๋ฏธ์ง๋ฅผ ํตํด์ ํ ๋ฒ ๋ ์ ๋ฆฌํด ๋ณด์.
- ์ด๋ฏธ์ง ์ถ์ฒ : https://tv.naver.com/v/23652451
์ ๊ทธ๋ฆผ์์๋ ํ์ธํ ์ ์๋ ๋์์ฑ๊ณผ ๋ณ๋ ฌ์ฑ์ ์ฐจ์ด๋ ๋ค์๊ณผ ๊ฐ๋ค.
๋์์ฑ์ ์ต์ ๋๊ฐ์ ๋
ผ๋ฆฌ์ ํ๋ฆ(task)๊ฐ ์กด์ฌํ๋ค. ๋์์ฑ์ ์ฑ๊ธ ์ฝ์ด(๋จ์ผ CPU) ์์๋ ๋์ํ๋ฉฐ, ๋ณ๋ ฌ์ฑ์ ๋ฉํฐ ์ฝ์ด(๋ค์ค CPU) ์์ ๋์ํ๋ค.
์ ๋ฆฌํด ๋ณด์๋ฉด, ๋์์ฑ์ด๋ ๋ ๊ฐ ์ด์์ ์์ ์ ์๊ฒ ๋๋๊ณ ์ฐ์ ์์์ ๋ฐ๋ผ์ ์์ ์ ํ์ ๋น ๋ฅด๊ฒ ํจ์ผ๋ก์ ์ฌ๋ฌ๊ฐ์ ์์ ๋ค์ด ๋ง์น ๋์์ ์คํ๋๋ ๊ฒ ์ฒ๋ผ ๋ณด์ด๊ฒ ํ๋ก๊ทธ๋จ์ ๊ตฌ์กฐํ ํ๋ ๋ฐฉ๋ฒ์ด๋ค.
๋ฆฌ์กํธ์์ ๋์์ฑ(concurrency)
๋ฆฌ์กํธ ๊ณต์๋ฌธ์์์๋ ๋์์ฑ์ ๋ํด์ ๋ค์๊ณผ ๊ฐ์ด ์ค๋ช ํ๋ค.
Concurrency is not a feature, per se. Itโs a new behind-the-scenes mechanism that enables React to prepare multiple versions of your UI at the same time.
Concurrency ์์ฒด๋ ๊ธฐ๋ฅ์ด ์๋๋ค. React๊ฐ ๋์์ ์ฌ๋ฌ ๋ฒ์ ์ UI๋ฅผ ์ค๋นํ ์ ์๊ฒ ํด์ฃผ๋ ์๋ก์ด ๋นํ์ธ๋ ๋ฉ์ปค๋์ฆ์ด๋ค.
A key property of Concurrent React is that rendering is interruptible. When you first upgrade to React 18, before adding any concurrent features, updates are rendered the same as in previous versions of React โ in a single, uninterrupted, synchronous transaction. With synchronous rendering, once an update starts rendering, nothing can interrupt it until the user can see the result on screen.
Concurrent React์ ํต์ฌ์ ๋ ๋๋ง ์์ ์ด ์ค๋จ ๊ฐ๋ฅํ๋ค๋ ๊ฒ์ด๋ค. React 18๋ก ์ฒ์ ์ ๊ทธ๋ ์ด๋ํ ๋ concurrent ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ธฐ ์ ์ ๋ฐ์ดํธ๋ ์ด์ ๋ฒ์ ์ React์ ๋์ผํ๊ฒ ์ค๋จ๋์ง ์๋ ๋จ์ผ ๋๊ธฐ์ ํธ๋์ญ์ ์ผ๋ก ๋ ๋๋ง ๋์๋ค. ๋๊ธฐ์ ๋ ๋๋ง์ ๊ฒฝ์ฐ ํ ๋ฒ ๋ ๋๋ง์ด ์์๋๋ฉด, ์ฌ์ฉ์๊ฐ ํ๋ฉด์์ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ ์์ ๋๊น์ง ๊ทธ ์ด๋ค ๊ฒ๋ ๋ ๋๋ง์ ๋ฐฉํดํ ์ ์์๋ค.
In a concurrent render, this is not always the case. React may start rendering an update, pause in the middle, then continue later. It may even abandon an in-progress render altogether. React guarantees that the UI will appear consistent even if a render is interrupted. โฆ
With this capability, React can prepare new screens in the background without blocking the main thread. This means the UI can respond immediately to user input even if itโs in the middle of a large rendering task, creating a fluid user experience.
Concurrent ๋ ๋๋ง์์๋ ํญ์ ๊ทธ๋ ์ง๋ ์๋ค. React๋ ์ ๋ฐ์ดํธ๋ ๋ ๋๋ง์ ์์ํ๊ณ ์ค๊ฐ์ ์ผ์ ์ค์งํ๋ค๊ฐ ๋์ค์ ๊ณ์ํ ์ ์๋ค. ์ฌ์ง์ด ์งํ ์ค์ธ ๋ ๋๋ง์ ์์ ํ ์ค๋จํ ์๋ ์๋ค. React๋ ๋ ๋๋ง์ด ์ค๋จ๋๋๋ผ๋ UI๊ฐ ์ผ๊ด๋๊ฒ ํ์๋๋๋ก ๋ณด์ฅํ๋ค.
์ด ๊ธฐ๋ฅ์ ํตํด React๋ ๋ฉ์ธ ์ค๋ ๋๋ฅผ ์ฐจ๋จํ์ง ์๊ณ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์ ํ๋ฉด์ ์ค๋นํ ์ ์๋ค. ์ฆ, UI๊ฐ ๋๊ท๋ชจ ๋ ๋๋ง ์์ ์ค์๋ ์ฌ์ฉ์ ์ ๋ ฅ์ ์ฆ์ ๋ฐ์ํ์ฌ ์ ๋์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ ์ ์๋ค.
๊ณต์๋ฌธ์์ ๋ด์ฉ์ ์ ๋ฆฌํด ๋ณด์๋ฉด, ๋ฆฌ์กํธ๊ฐ ๋งํ๋ ๋์์ฑ ๋ ๋๋ง์ด๋,
- ๋์์ฑ ๊ฐ๋ ์ ํ์ฉํด์ ํ ๋ฒ ์์ํ๋ฉด ๋ฉ์ถ ์ ์์๋ ๋ ๋๋ง ์์ ์ ๋ฉ์ถ๊ฑฐ๋,
- ์ฐ์ ์์๋ฅผ ์ ํด์ ๋ ์ฐ์ ์์๊ฐ ๋์ ๋ ๋๋ง ์์ ์ ์ํํด ์ฌ๋ฌ ๋ฒ์ ผ์ UI๋ฅผ ๋ง๋ค๊ณ ,
- ๊ทธ ์ค ์ฌ์ฉ์ ์ ๋ ฅ๊ณผ ๊ฐ์ ์ธํฐ๋ ์ ์ ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ๋ฐ์ํ ์ ์๋ UI๋ฅผ ์ ํํ๋ ๊ฒ์ ๋งํ๋ค.
๋์์ฑ ๋ ๋๋ง์ ํต์ฌ์ ์ฌ๋ฌ ์์ ์ ๋์์ ์คํํ๋ ๊ฒ ์ฒ๋ผ ๋ณด์ด๊ฒ ํด์ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๋ ๊ฒ์ด๋ค.(ํต์ฌ์ ์ฌ์ฉ์ ๊ฒฝํ!)
๊ทธ๋ ๋ค๋ฉด, ์ด๋ค ์ํฉ์์ ๋์์ฑ ๊ฐ๋ ์ด ํ์ํ๊ฒ ๋ ๊น? ๐ค
๐ญ Blocking Rendering
๋ธ๋ผ์ฐ์ ์ ๋ฉ์ธ ์ค๋ ๋๋ ์ฑ๊ธ ์ค๋ ๋๋ผ์ ํ ๋ฒ์ ํ๋์ ์์ ๋ง ์ฒ๋ฆฌํ ์ ์๋ค.
์ฆ HTML์ ํ์ฑ, Javascript ํ์ผ์ ๋ค์ด๋ก๋ ํ๊ณ ์คํ, ์ฌ์ฉ์์ ํ๋์ผ๋ก ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌ, ๋ฆฌํ์ธํธ, ๋ฆฌํ๋ก์ฐ ๋ฑ์ ๋ชจ๋ ๋จ์ผ ๋ฉ์ธ ์ค๋ ๋์์ ์ฒ๋ฆฌํ๋ค.๊ทธ๋ฆฌ๊ณ , ๋ฉ์ธ ์ค๋ ๋์์ ์ด๋ค ์์ ์ด ์คํ๋๋ฉด ๊ทธ ์์ ์ด ๋๋ ๋๊น์ง ๋ฉ์ถ ์ ์์๋ค.
์ด๋ฅผ Blocking Rendering ์ด๋ผ๊ณ ํ๋ค.
๋ฆฌ์กํธ์์์ ๋ ๋๋ง ์ฆ, ํ๋ฉด์ ๊ทธ๋ฆฌ๋ ์์ , ์ฌ๊ท์ ์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํด์ ์ด์ ๋ ๋๋ง๊ณผ ๋น๊ตํด ๋ค๋ฅด๊ฒ ๋ณด์ฌ์ผ ํ๋ UI๋ฅผ ํ์ ํ๊ณ (render phase) ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ธ๋ผ์ฐ์ ์ ์ปค๋ฐํด(commit phase) ์ค์ ์ฌ์ฉ์์ ๋์ ๋ณด์ด๋ ์์ ์ด ํ ๋ฒ ์์๋๋ฉด ๋ฉ์ถ ์ ์๋ ์์ ์ด์๋ค.
๋ณดํต์ ์ํฉ์์๋ ํ ๋ฒ ์์๋๋ฉด ๋ฉ์ถ ์ ์๋ ๋ฆฌ์กํธ์ ๋ ๋๋ง ์์ ์ด ์ฌ์ฉ์ ๊ฒฝํ์ ํฐ ์ํฅ์ ์ฃผ์ง ์๋๋ค. ๋ฆฌ์กํธ์ ๋ณ๊ฒฝ ๋น๊ต ์๊ณ ๋ฆฌ์ฆ์ด ๋งค์ฐ ๋น ๋ฅด๊ธฐ ๋๋ฌธ์ด๋ค.
ํ์ง๋ง, ๋ค์๊ณผ ๊ฐ์ ํน์ํ ์ํฉ์ ์๊ฐํด๋ณด์.
import React, { useState } from "react"
function App() {
const [text, setText] = useState("")
return (
<div className="container">
<h1>Blocking ({text.length})</h1>
<input
type="text"
value={text}
maxLength={100}
onChange={({ target }) => {
setText(target.value)
}}
/>
<ColorList length={text.length} />
</div>
)
}
input ์ ์ ๋ ฅ์ ํ ๋๋ง๋ค, App ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋๋ฉฐ ColorList ๋ํ ๋ ๋๋ง ๋๋ค. ์ฌ๊ธฐ์, ColorList๋ ๋ฌด๊ฑฐ์ด ์ฐ์ฐ์ ์ํํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ํ ์คํธ๊ฐ UI์ ๋ฐ๋ก ๋ฐ์๋์ง ์์ ์ข์ง ๋ชปํ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ ์ ์๋ค.
concurrent features
์ ์ฌ์ฉํ์ง ์๋ ๋ฆฌ์กํธ์์ ๋ ๋๋ง์ ํ ๋ฒ ์์ํ๋ฉด ๋ฉ์ถ ์ ์๋ ์์
์ด์ฌ์, ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ํ
์คํธ๋ฅผ UI์ ๋ฐ์ํด์ค์ผ ํ๋ ์ฌ์ฉ์ ๊ฒฝํ ๊ธฐ์ค ๋์ ์ฐ์ ์์ ์์
์ด ColorList ์ปดํฌ๋ํธ ๋ ๋๋ง์ ์ํด ๋ฐ๋ฆฌ๊ฒ ๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ๋ฆฌ์กํธ 18 ๋ฒ์ ผ๋ถํฐ ์ฌ์ฉํ ์ ์๋ concurrent features ๋ฅผ ์ฌ์ฉํด์ ํด๊ฒฐํ ์ ์๋ค.
์ฌ์ฉ์๊ฐ ๋ฐ์์ํค๋ ํน์ ์ด๋ฒคํธ์ ๋ ๋น ๋ฅด๊ฒ ๋ฐ์ํ ์ ์๋ UI๋ฅผ ์ฐ์ ์ํ๊ณ , ํ์ฌ ๋ ๋๋ง ์์ ์ ์ผ์์ ์ผ๋ก ์ค๋จํ ์ ์๋๋ก ํ ์ ์๋ค.
์ฆ, ๋ ๋น ๋ฅด๊ฒ ๋ฐ์ํด์ผ ํ๋ ์์ (input UI ํ์)์ด ์คํ๋๋ฉด, ํ์ฌ ๋ ๋๋ง(ColorList ๋ ๋๋ง)์ ์ผ์ ์ค๋จํ๊ณ ์ฐ์ ์์ ์ ๋จผ์ ์ฒ๋ฆฌํ๋ค.
์ด์ ์ด๋ค concurrent features๊ฐ ์๋์ง ์์๋ณด์.
โจ useTransition
๊ณต์๋ฌธ์์์ useTransition ํ ์ ๋ค์๊ณผ ๊ฐ์ด ์ค๋ช ํ๋ค.
useTransition is a React Hook that lets you update the state without blocking the UI.
useTransition์ UI๋ฅผ ์ฐจ๋จํ์ง ์๊ณ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ ์ ์๋ ๋ฆฌ์กํธ ํ ์ด๋ค.
์ฌ๊ธฐ์ UI๋ฅผ ์ฐจ๋จํ์ง ์๋๋ค๋ ๊ฒ์, ์ฌ์ฉ์์ ์ธํฐ๋ ์ ์ ์ฆ๊ฐ์ ์ผ๋ก UI์ ๋ฐ์ํด์ผ ํ ๋ ์ด์ ํ๊ณ ์๋ ๋ฌด๊ฑฐ์ด ๋ ๋๋ง ์์ ์ด ๋ค์ UI ๋ ๋๋ง์ ์ฐจ๋จํ์ง ์์์ผ ํ๋ค๋ ๋ป์ด๋ค. ๋ ๋๋ง ์์ ์ด ์ธ์ ์ํ๋๊ณ ์๋ , ๋ ๊ธํ ์ํ ์ ๋ฐ์ดํธ๋ก ์ธํด์ ์ค๋จ๋ ์ ์์์ ์๋ฏธํ๋ค.
const [isPending, startTransition] = useTransition()
useTransition
ํ
์์ ์ ๊ณตํ๋ startTransition
ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ํ ์
๋ฐ์ดํธ๊ฐ ๊ธด๊ธํ์ง ์๋ค๋ ๊ฒ์ ํ์ํ ์ ์๋ค. ๋น ๋ฅธ UI ์
๋ฐ์ดํธ, ๋ฐ์์ ๋ฐฉํดํ ์ ์๋ ์ํ ์
๋ฐ์ดํธ๊ฐ ๊ธด๊ธํ์ง ์๋ค๋ ๊ฒ์ ์ํ ์
๋ฐ์ดํธ๋ฅผ โํธ๋์ง์
โ์ผ๋ก ํ์ํด์ ๋ฆฌ์กํธ์๊ฒ ์๋ ค ์๋์ ์ผ๋ก ์ฐ์ ์์๋ฅผ ์กฐ์ ํ ์ ์๋ค.
(a ์ํ ์ ๋ฐ์ดํธ? ๊ธํ์ง ์์ต๋๋ค! ํด๋น ์ํ ์ ๋ฐ์ดํธ๋ณด๋ค ๋ ์ค์ํ ์์ ์ด ์๋ค๋ฉด ๊ทธ๊ฒ๋ถํฐ ํด์ฃผ์ธ์~ ์ ๊ฐ์ ์์ฒญ)
์ฆ, ์ํ ์ ๋ฐ์ดํธ๊ฐ ๋์์ฑ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง ์๊ณ ๋๊ธฐ์ ์ผ๋ก ๋ ๋๋ง ๋ ๊ฒฝ์ฐ ์ ์ฌ์ ์ผ๋ก ์ฌ์ฉ์์ ๊ฒฝํ์ ๋์ ์ํฅ์ ๋ฏธ์น ์ ์๋ค๊ณ ๋ฆฌ์กํธ์๊ฒ ์๋ฆฌ๋ ๊ฒ์ด๋ค.
์ Input
, ColorList
์ปดํฌ๋ํธ ์์๋ฅผ ๋ค์ ์๊ฐํด๋ณด๋ฉด ์ฌ์ฉ์๊ฐ ํ์ฌ ์ด๋ค ๊ฐ์ ์
๋ ฅํด ์คฌ๋์ง๋ฅผ UI์ ํ์ํด์ฃผ๋ ์์
์ด ๋ ์ฐ์ ์์๊ฐ ๋์ ์์
์ด๋ผ๊ณ ํ ์ ์๋ค.
startTransition API
๋ฅผ ์ฌ์ฉํด์ ์ํ ์
๋ฐ์ดํธ๋ฅผ ๊ธด๊ธํ์ง ์์ ๊ฒ์ผ๋ก ๊ฐ์ฃผํด์ ๋ฌด๊ฑฐ์ด ๋ ๋๋ง ์์
์ธ ColorList ์ปดํฌ๋ํธ ๋ ๋๋ง ์์
์ ๋ค๋ก ๋ฏธ๋ค๋ณด์.
import React, { useState, useTransition } from "react"
function TextInput({ onChange }) {
const [text, setText] = useState("")
return (
<input
type="text"
value={text}
onChange={({ target }) => {
setText(target.value)
onChange(target.value)
}}
/>
)
}
function App() {
const [size, setSize] = useState(0)
const [isPending, startTransition] = useTransition()
function handleChange(text) {
startTransition(() => {
setSize(text.length)
})
}
return (
<div className="container">
<h1>Concurrent ({size})</h1>
<TextInput onChange={handleChange} />
<div className={isPending ? "pending" : ""}>
<ColorList length={size} />
</div>
</div>
)
}
export default App
ColorList
์ปดํฌ๋ํธ๊ฐ props๋ก ๋ฐ๋ size ์ํ๋ฅผ ๋ฐ๋ก ๋ถ๋ฆฌํ๊ณ ํด๋น ์ํ ์
๋ฐ์ดํธ๊ฐ ์ฐ์ ์์๊ฐ ๋ฎ์ ์ํ ์
๋ฐ์ดํธ๋ผ๋ ๊ฒ์ ๋ฆฌ์กํธ์๊ฒ ์๋ฆฐ๋ค.
React can prepare new screens in the background without blocking the main thread.
React๋ ๋ฉ์ธ ์ค๋ ๋๋ฅผ ์ฐจ๋จํ์ง ์๊ณ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์ ํ๋ฉด์ ์ค๋นํ ์ ์๋ค.
์ถ์ฒ : ๋ฆฌ์กํธ ๊ณต์๋ฌธ์
๋ฆฌ์กํธ๋ ์ด์ size
์ํ ์
๋ฐ์ดํธ๊ฐ ๋ฌด๊ฑฐ์ด ๋ ๋๋ง์ ์ ๋ฐํ๋ ๊ฒ์์ ์๊ธฐ ๋๋ฌธ์, ์
๋ฐ์ดํธ๋ฅผ ์ฆ์ ๋ฐ์ํ๋ ๋์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์๋ก์ด ์ํ๋ฅผ ์ค๋นํ๋ฉด์ ํ์ฌ์ UI๋ฅผ ์ธํฐ๋ํฐ๋ธํ๊ฒ ์ ์งํ๋ค.
useTransition
ํ
์ด ์ ๊ณตํ๋ isPending ๋ถ๋ฆฌ์ธ ๊ฐ์ ์ฌ์ฉํด์ ๊ธด๊ธํ์ง ์์ ์ํ ์
๋ฐ์ดํธ์ ์งํ ์ํ๋ฅผ ์ ์ ์๊ณ , ์ด๋ฅผ ์ฌ์ฉํด ์ฌ์ฉ์์๊ฒ loading feedback ๋ํ ์ ๊ณตํ ์ ์๊ฒ ๋๋ค.
<div className={isPending ? "pending" : ""}>
{isPending && <h1>loading...</h1>}
<ColorList length={size} />
</div>
โจ useDeferredValue
๊ณต์๋ฌธ์์์ useDeferredValue
ํ
์ ๋ค์๊ณผ ๊ฐ์ด ์ค๋ช
ํ๋ค.
useDeferredValue is a React Hook that lets you defer updating a part of the UI.
useDeferredValue๋ UI ์ผ๋ถ ์ ๋ฐ์ดํธ๋ฅผ ์ง์ฐ์ํฌ ์ ์๋ React Hook์ด๋ค.
useTransition
ํ
์ด ์ ๊ณตํ๋ startTransition
์ ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ ํจ์๋ฅผ ๋ํํด์ ํด๋น ์์
์ ์ฐ์ ์์๊ฐ ๋ฎ๋ค๋ ๊ฒ์ ๋ฆฌ์กํธ์๊ฒ ์๋ฆฌ์ง๋ง, useDeferredValue
ํ
์ ์ธ์๋ก ๋ค์ด์ค๋ ๊ฐ ์
๋ฐ์ดํธ์ ์ฐ์ ์์๊ฐ ๋ฎ๋ค๋ ๊ฒ์ ์๋ฆฐ๋ค.
const deferredValue = useDeferredValue(value)
๋ง์ฝ ๊ฐ์ ๋ณ๊ฒฝ์ผ๋ก ์ธํด์ ๋ฌด๊ฑฐ์ด ๋ ๋๋ง ์์ ์ด ์ํ๋๋ค๋ฉด, ํด๋น ํ ์ผ๋ก ๊ฐ์ผ ํ ๋ฌด๊ฑฐ์ด ๋ ๋๋ง์ ์ง์ฐ์ํฌ ์ ์๊ฒ ๋๋ค.
์ด๋ฒ์๋ ์ ์์๋ฅผ useDeferredValue ํ ์ ์ฌ์ฉํด์ ๊ฐ์ ํด๋ณด์.
import React, { useState, useDeferredValue } from "react"
function TextInput({ onChange }) {
const [text, setText] = useState("")
return (
<input
type="text"
value={text}
onChange={({ target }) => {
setText(target.value)
onChange(target.value)
}}
/>
)
}
function App() {
const [size, setSize] = useState(0)
const deferredSize = useDeferredValue(size)
function handleChange(text) {
setSize(text.length)
}
return (
<div className="container">
<h1>Concurrent ({size})</h1>
<TextInput onChange={handleChange} />
<div className={deferredSize !== size ? "pending" : ""}>
<ColorList length={deferredSize} />
</div>
</div>
)
}
export default App
๋ฌด๊ฑฐ์ด ๋ ๋๋ง์ ์ ๋ฐํ๋ ๊ฐ์ธ size
์
๋ฐ์ดํธ์ ์ฐ์ ์์๋ฅผ ๋ฎ์ถฐ์ UI๋ฅผ ์ธํฐ๋ํฐ๋ธํ๊ฒ ์ ์ง๋ ์ ์๊ฒ ํ๋ค.
(๊ฒฐ๊ณผ๋ useTransition๊ณผ ๊ฐ๋ค.)
useDeferredValue ํ ์ ์ง์ฐํด์ผ ํ๋ ๊ฐ ์ ๋ฐ์ดํธ ์ง์ ์ ์ดํ ์ ์๊ณ , props๋ก ์ ๋ฌ๋ฐ์ ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
function SomeComponent({ value }) {
const deferredValue = useDeferredValue(size)
// heavy work using deferredValue
return <JSX />
}
๐ง ์ ๋ฆฌ
- ๋ฆฌ์กํธ๋ ๋์์ฑ ๊ธฐ๋ฅ์ ๋์ ํด์, ์์ํ๋ฉด ๋ฉ์ถ ์ ์์๋ ๋ ๋๋ง ๊ณผ์ ์ ์ผ์ ์ค์งํ๋ค๊ฐ ๋์ค์ ๋ค์ ์์ํ๊ฑฐ๋ ์ค๋จํ ์ ์๊ฒ ๋์๋ค. ์ด๋ ๋ฌด๊ฑฐ์ด ๋ ๋๋ง ์์ ์ด ์งํ๋๊ณ ์๋๋ผ๋ ์ฌ์ฉ์ ์ ๋ ฅ๊ณผ ๊ฐ์ ๋ ๋น ๋ฅธ ๋ฐ์์ ํด์ผ ํ๋ ์ํฉ์ ๋ํด UI๊ฐ ์ฆ๊ฐ์ ์ผ๋ก ๋ฐ์ํด ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํฌ ์ ์๊ฒ ๋์๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
- ๋ฆฌ์กํธ๋ ์ฑ ์ ์ฒด ๋์์ฑ ๋ชจ๋๋ ์กด์ฌํ์ง ์๊ณ , concurrent features ๋ฅผ ํตํด ๋ถ๋ถ์ ์ผ๋ก ๋์์ฑ ๊ธฐ๋ฅ์ ํ์ฉํ ์ ์์ผ๋ฉฐ, ์ด๋ค ์ํฉ์ ์ด๋์ ์ ์ฉํ ์ง๋ ๊ฐ๋ฐ์์ธ ์ฐ๋ฆฌ๊ฐ ๊ฒฐ์ ํด์ผ ํ๋ค.
- ์ํ๋ฅผ ์
๋ฐ์ดํธ ํ๋ ์์
(size ์ํ ์
๋ฐ์ดํธ), ๋ ๋๋ง ์์
(
์ปดํฌ๋ํธ ๋ ๋๋ง)์ ์๊ฒ ๋๋๊ณ ์ฐ์ ์์๋ฅผ ์ ํ ํ ๋น ๋ฅธ Context Switching์ ํตํด์ ๋ง์น ๋ ์์ ์ด ๋์์ ์คํ๋๋ ๊ฒ ์ฒ๋ผ ๋ณด์ด๊ฒ ํ๋ค. - useTransition ํ ์ โํน์ ์ํ ์ ๋ฐ์ดํธโ๋ฅผ ์ง์ฐ์์ผ์ ๋ฌด๊ฑฐ์ด ๋ ๋๋ง ์์ ์ ๋ค๋ก ๋ฏธ๋ฃฐ ์ ์๋๋ก ํ๋ค.
- useDeferredValue ํ ์ โ๊ฐโ ์ ๋ฐ์ดํธ๋ฅผ ์ง์ฐ์์ผ์ ๋ฌด๊ฑฐ์ด ๋ ๋๋ง ์์ ์ ๋ค๋ก ๋ฏธ๋ฃฐ ์ ์๋๋ก ํ๋ค.
- โจ ๋ฆฌ์กํธ ๋์์ฑ ๋ ๋๋ง์ ํต์ฌ์ ์ฌ์ฉ์ ๊ฒฝํ ํฅ์์ด๋ค!