React 18์์ ๋์ ๋ Concurrent Features(๋์์ฑ)์ ํต์ฌ ๊ฐ๋ ๋ค๊ณผ ์ด๊ฒ์ด ํด๊ฒฐํ๊ณ ์ ํ๋ ๋ฌธ์ ๋ค์ ์์ธํ ์ดํด๋ณด์์ต๋๋ค.
Concurrent Features (๋์์ฑ)
Tearing (ํฐ์ด๋ง)
State as a Snapshot (์ค๋
์ท์ผ๋ก์์ ์ํ)
Blocking vs Non-blocking Rendering
์ฐ์๋ ์ํ ์
๋ฐ์ดํธ์ ์ฒ๋ฆฌ
๋ฐฐ์น ์
๋ฐ์ดํธ์ ํ๊ณ
์นดํ์์ ์ฃผ๋ฌธ์ ๋ฐ๋ ์ํฉ์ผ๋ก ๋น์ ํด๋ณผ๊ฒ์!
React 18 ์ด์ : ํ ๋ช ์ ์ง์์ด ์ฃผ๋ฌธ์ ๋ฐ๊ณ ์๋ฃ๋ฅผ ๋ง๋๋ ์ํฉ
์ด๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด React 18์์๋ ์ฌ๋ฌ ๊ฐ์ง ์๋ก์ด ๊ธฐ๋ฅ์ ๋์ ํ์ด์!
๋ณต์กํ ์ผํ๋ชฐ ํ์ด์ง๋ฅผ ์๋ก ๋ค์ด๋ณผ๊น์?
์ด์ ๋ฐฉ์:
// ๊ธฐ์กด React (๋๊ธฐ์ ๋ ๋๋ง)
function ProductList() {
const [products, setProducts] = useState([]);
useEffect(() => {
// ๋ฌด๊ฑฐ์ด API ํธ์ถ
fetchProducts().then(data => setProducts(data));
}, []);
// ๋ฌธ์ : API ์๋ต์ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ์ ์ฒด UI๊ฐ ๋ธ๋ก๋จ
return <div>{/* ์ ํ ๋ชฉ๋ก ๋ ๋๋ง */}</div>;
}
์๋ก์ด ๋ฐฉ์:
function ProductList() {
const [isPending, startTransition] = useTransition();
const [products, setProducts] = useState([]);
const loadProducts = () => {
// ๋ฎ์ ์ฐ์ ์์๋ก ํ์
startTransition(() => {
fetchProducts().then(data => setProducts(data));
});
};
return (
<div>
{isPending ? (
// ์ค์ผ๋ ํค UI๋ ๋ก๋ฉ ํ์
<SkeletonLoader />
) : (
// ์ค์ ์ ํ ๋ชฉ๋ก
<ProductGrid products={products} />
)}
{/* ์ด ๋ถ๋ถ์ ๊ณ์ ๋ฐ์ ๊ฐ๋ฅ! */}
<SearchBar />
<FilterOptions />
</div>
);
}
์ค์๊ฐ ์ฃผ์ ๊ฐ๊ฒฉ ํ์ ์ฑ์ ์๋ก ๋ค์ด๋ณผ๊ฒ์:
๋ฌธ์ ์ํฉ:
// ์ ์ญ ์ฃผ์ ๊ฐ๊ฒฉ
let stockPrice = 1000;
function StockWidget() {
// ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ๊ฐ์ ๊ฐ๊ฒฉ์ ํ์ํ๋๋ฐ...
const [price, setPrice] = useState(stockPrice);
// ๊ฐ๊ฒฉ์ด ๋ฐ๋๋ฉด ์
๋ฐ์ดํธ
useEffect(() => {
const handler = () => setPrice(stockPrice);
subscribe(handler);
return () => unsubscribe(handler);
}, []);
return <div>ํ์ฌ ๊ฐ๊ฒฉ: {price}์</div>;
}
๋ฌธ์ ์ :
ํด๊ฒฐ๋ฐฉ๋ฒ:
function StockWidget() {
// useSyncExternalStore๋ก ํด๊ฒฐ
const price = useSyncExternalStore(
subscribe,
() => stockPrice
);
return <div>ํ์ฌ ๊ฐ๊ฒฉ: {price}์</div>;
}
๋ ๋ถ๋๋ฌ์ด ์ฌ์ฉ์ ๊ฒฝํ
์์ ์ ์ธ ๋ฐ์ดํฐ ํ์
๊ฐ๋ฐ์ ๊ฒฝํ ๊ฐ์
์ค์ ์ ์ฉ ์์๋:
1. ๋ฌด๊ฑฐ์ด ์์
์ startTransition์ผ๋ก ๊ฐ์ธ๊ธฐ
2. ์ธ๋ถ ์ํ ์ฌ์ฉ ์ ์ ์ ํ ๋๊ตฌ ์ ํํ๊ธฐ (Zustand ๋ฑ)
3. ๋ก๋ฉ ์ํ์ ๋ํ UI ์ค๋นํ๊ธฐ (์ค์ผ๋ ํค ๋ฑ)