๐ ์?
โผ React๋ SPA๋ก, ์ฌ์ฉ์๊ฐ ์ฒ์ ๋ฉ์ธ ํ์ด์ง์ ์ ์ํ๋ฉด, ๋ชจ๋ js ํ์ผ์ ๋ค์ด๋ก๋ ํ์ฌ ์ด๊ธฐ ๋ก๋ฉ ์๋๊ฐ ๋๋ ค, ์ฑ๋ฅ ๊ฐ์ ์์ ์ ์ํ ๋ฐฉ๋ฒ์ ๋ํด์ ์์๋ณด๊ณ ์ ํ๋ค.
๐ React ์ฑ๋ฅ ๊ฐ์ ํ๊ธฐ
โ ๊ฐ๋ฐ ๋๊ตฌ ์ค์น
โผ React Developer Tools๋ฅผ ์ค์นํ๋ค.
โผ Components ์ฐฝ์์ Component์ ๊ตฌ์กฐ, Props ๋ฑ์ ํ์ธํ ์ ์๋ค.
โผ Profiler ์ฐฝ์์ ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํ๊ณ ์๋ Component๋ฅผ ์ฐพ์ ์ ์๋ค. (๋ นํ ๋ฒํผ์ ๋๋ฅด๊ณ ํ์ด์ง ์ด๋ ๋ฐ ๋ฒํผ ํด๋ฆญ ๋ฑ ์ฌ์ฉํ๋ค ๋ณด๋ฉด Component ๋ณ๋ก ๋ ๋๋ง ์๋๋ฅผ ์๋ ค์ค๋ค.)
๐ฅ ๋๋ถ๋ถ์ ์ง์ฐ์ ์๋ฒ์ ํต์ ์ด ๋๋ฆฐ ๊ฒ
โ Lazy ๋ก๋ฉ
โผ React๋ SPA์ด๊ธฐ ๋๋ฌธ์, ํ๋์ html, js, css ํ์ผ์ ๋ชจ๋ ์ฝ๋๊ฐ ๋ค์ด ์๊ณ , ์ฌ์ฉ์๊ฐ ๋ฉ์ธ ํ์ด์ง์ ์ ์ํ๋ฉด ํฐ js ํ์ผ์ ๋ค์ด ๋ฐ๊ธฐ ๋๋ฌธ์, ์ฒ์ ๋ ๋๋ง ์๋๊ฐ ๋๋ ค์ง๋ค.
โผ ๋ฐ๋ผ์, ๋ฉ์ธ ํ์ด์ง์ ์ ์ํ ๋, ์ฌ์ฉํ์ง ์๋ Component๋ค์ ๋จผ์ ๋ก๋ ์ํค์ง ์๋๋ก Lazy ๋ก๋ฉ์ ์ฌ์ฉํ ์ ์๋ค.
import Detail from "pages/items/item"; // ์ฌ์ฉ X
const Detail = lazy(() => import("pages/items/detail"));
โผ ์์ ๊ฐ์ด import ๋ฌธ์ ์ ๊ฑฐํ๊ณ , lazy()๋ฅผ ์ฌ์ฉํ์ฌ Detail์ Lazy ๋ก๋ฉํ ์ ์๋ค.
โผ Lazy ๋ก๋ฉ์ ํ๋ฉด, ํด๋น Component๋ ๋น๋ ์, ๋ณ๋์ js ํ์ผ๋ก ๋ถ๋ฆฌ๋๋ค.
โผ ์ฌ์ฉ์๊ฐ Detail Component๋ฅผ ์ฌ์ฉํ๊ฒ ๋ ๋, ๋ก๋ฉ์ด ์ด๋ฃจ์ด์ง๋ฏ๋ก ์ง์ฐ ์๊ฐ์ด ๋ฐ์ํ ์ ์๋ค.
import React, { Suspense, lazy } from "react";
const Detail = lazy(() => import("pages/items/detail"));
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Route
path="/detail/:id"
element={
<Suspense fallback={<div>๋ก๋ฉ ์ค...</div>}>
<Detail />
</Suspense>
}
/>
);
โผ Suspend Component๋ฅผ ์ฌ์ฉํด์ ์ง์ฐ ์๊ฐ ๋์ ๋ค๋ฅธ Element๋ฅผ ํ๋ฉด์ ์ถ๋ ฅํ ์ ์๋ค.
โผ Lazy ๋ก๋ฉ์ ์ฌ์ฉํ ๊ฒ์ด๋ผ๋ฉด ๋ฐ๋์ ์ฌ์ฉํ๋๊ฒ ์ข๋ค.
import React, { Suspense, lazy } from "react";
const Detail = lazy(() => import("pages/items/detail"));
const Cart = lazy(() => import("pages/cart/cart"));
const queryClient = new QueryClient();
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<Suspense fallback={<div>๋ก๋ฉ ์ค...</div>}>
<Routes>
<Route path="/detail/:id" element={<Detail />} />
<Route path="/cart" element={<Cart />}></Route>
</Routes>
</Suspense>
</BrowserRouter>
);
โผ Routes Component ์์ ์ฌ๋ฌ ๊ฐ์ Lazy Component๊ฐ ์์ผ๋ฉด, ์์ ๊ฐ์ด Routes Component ์์ Suspend Component๋ฅผ ์์ฑํ์ฌ ์ฌ์ฉํ ์ ์๋ค.
โ ์์ Component ์ฌ๋ ๋๋ง ๋ง๊ธฐ
โผ React์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ถ๋ชจ Component๊ฐ ์ฌ๋ ๋๋ง๋๋ฉด, ์์ Component๋ ์ฌ๋ ๋๋ง๋๋ค.
โผ ๋ถ๋ชจ Component๋ง ์ฌ๋ ๋๋งํ๋ฉด ๋๋ ์ํฉ์ ์ฌ์ฉํ์ฌ, ์์ Component ์ฌ๋ ๋๋ง ๋น์ฉ์ ๋ง์ ์ ์๋ค.
import { memo } from "react";
const CartBody = memo(({ item }) => {
return (
<tr>
<td>{item.id}</td>
<td>{item.title}</td>
<td>{"count" in item ? item.count : 0}</td>
<td>{item.price}</td>
</tr>
);
});
export default CartBody;
โผ Component๋ฅผ ์์ฑํ ๋, memo๋ฅผ ์ฌ์ฉํด์ ๊ฐ์ธ๋ฉด, ์์ Component๋ ์ฌ๋ ๋๋งํ์ง ์๋๋ค.
๐ฅ ์์ Component์์ ์ฌ์ฉํ๋ Props์ ๊ฐ์ด ๋ณํ๋ฉด ์ฌ๋ ๋๋ง์ด ๋ฐ์ํ๋ค.
โผ memo๋ฅผ ์ฌ์ฉํ๋ฉด ๊ธฐ์กด props๋ ์ ๊ท props๋ ๋น๊ต ์ฐ์ฐ์ด ์ด๋ฃจ์ด์ง๊ณ , ๋ค๋ฅด๋ฉด ์ฌ๋ ๋๋ง์ ์งํํ๋ค.
โผ Props ๋น๊ต ์ฐ์ฐ์ด ์ด๋ฃจ์ด์ง๊ธฐ ๋๋ฌธ์, ์ฌ๋ ๋๋ง์ด ๋ฌด๊ฑฐ์ด Component์๋ง ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
โ ๋ฌด๊ฑฐ์ด ์ฐ์ฐ์ ํจ์ ์คํ์ Component Mount ์์๋ง ๋์
import { useMemo } from "react";
const heavy = () => {
for (let i = 0; i < 1000000; i++) {
console.log(i);
}
};
const CartBody = memo(({ item }) => {
const result = useMemo(() => {
heavy();
});
return (
<tr>
<td>{item.id}</td>
<td>{item.title}</td>
<td>{"count" in item ? item.count : 0}</td>
<td>{item.price}</td>
</tr>
);
});
export default CartBody;
โผ ํจ์์ ์คํ์ Component์ mount ์์ ์๋ง ๋์ํ๋๋ก ๋ณด์ฅํด์ค๋ค.
โผ ์ฝ๋ฐฑ ํจ์ ๋ค์ ๋ณํ ๊ฐ์ง state Array๋ฅผ ์ค์ ํด์ ํด๋น state๊ฐ ๋ณ๊ฒฝ๋๋ฉด, ํจ์๊ฐ ์คํ๋๊ฒ ํ ์ ์๋ค.
โผ useEffect์ ์ฌ์ฉ๋ฒ์ด ๋์ผํ๋ค.
๐ฌ useEffect๋ return()์ผ๋ก ๊ธฐ์ ํ html ์ฝ๋๊ฐ ๋ ๋๋ง ๋ ํ, ํจ์๊ฐ ์คํ๋๋ ๋ฐ๋ฉด, useMemo๋ html ์ฝ๋๊ฐ ๋ ๋๋ง ๋ ๋, ๋์์ ํจ์๊ฐ ์คํ๋๋ค.
โ Input ๊ฐ ๋ณ๊ฒฝ์ผ๋ก ์ธํ State ์ ์ฑ๋ฅ ์ ํ ๋ฐ์ ํด๊ฒฐ
const Test = () => {
let [inputVal, setInputVal] = useState("");
const heavy = new Array(100000).fill(0);
return (
<div>
<input
type="text"
onChange={(e) => {
startTransition(() => {
setInputVal(e.target.value);
});
}}
></input>
{heavy.map(() => (
<div>{inputVal}</div>
))}
</div>
);
}
โผ input ์ ๋ ฅ ๊ฐ์ด ๋ณํ ๋๋ง๋ค, ์ฌ๋ ๋๋ง์ด ์ผ์ด๋ heavy๋ผ๋ ๋ฌด๊ฑฐ์ด ์ฐ์ฐ์ด ๊ณ์ ์คํ๋๋ค.
import { useState, useTransition } from "react";
const Test = () => {
let [inputVal, setInputVal] = useState("");
let [isPending, startTransition] = useTransition();
const heavy = new Array(100000).fill(0);
return (
<div>
<input
type="text"
onChange={(e) => {
startTransition(() => {
setInputVal(e.target.value);
});
}}
></input>
{heavy.map(() => (
<div>{inputVal}</div>
))}
</div>
);
}
โผ useTransition์ ์ฌ์ฉํด์ state ๋ณํ๋ก ์ธํ ์ฑ๋ฅ ์ ํ๋ฅผ ์ค์ฌ์ค ์ ์๋ค.
โผ startTransition ํจ์๋ก state ๋ณํ๊ฐ ๋ฐ์ํ๋ ๋ถ๋ถ์ ๊ฐ์ธ์ค๋ค.
โผ ๋ธ๋ผ์ฐ์ ๋ ์ฑ๊ธ ์ค๋ ๋๋ก ๋์์ ์ฌ๋ฌ ์์ ์ ์ฒ๋ฆฌํ ์ ์๋ค. ๊ทธ๋ฐ๋ฐ input ๊ฐ์ ๋ณ๊ฒฝ์ ๋ณด์ฌ์ฃผ๊ณ , input ๊ฐ์ ๋ณ๊ฒฝ์ผ๋ก ์ธํด ์ฌ๋ ๋๋ง์ด ์ผ์ด๋ <div> ํ๊ทธ๋ฅผ ๋ณ๊ฒฝ๋ state๋ฅผ ํ์ฉํด, ๊ณ์ ์์ฑํ๋ ค๋ ์์ ์ด ์ถฉ๋ํ๊ฒ ๋๋ค.
โผ startTransition์ผ๋ก ๊ฐ์ธ์ง ์ฝ๋๋ ๋ฆ๊ฒ ์คํ์์ผ ์ฃผ๊ธฐ ๋๋ฌธ์, ๋์์ ํ๋ ค๋ ์์ ์ผ๋ก ๋๋ ค์ง๋ ํ์์ ํ์ด์ค๋ค.
โผ isPending์ startTransition์ผ๋ก ๊ฐ์ผ ํจ์๊ฐ ์คํ ์ค์ด๋ฉด true๋ฅผ ๋ฐํํ๋ค.
import { useState, useDeferredValue } from "react";
const Test = () => {
let [inputVal, setInputVal] = useState("");
let state = useDeferredValue(inputVal);
const heavy = new Array(100000).fill(0);
return (
<div>
<input
type="text"
onChange={(e) => {
setInputVal(e.target.value);
});
></input>
{heavy.map(() => (
<div>{state}</div>
))}
</div>
);
}
โผ ์ ์ฝ๋์ ๊ฐ์ ์ญํ ์ ํ๋ ์ฝ๋๋ก useDeferredValue๋ก ์ค์ ํ state๋ก ํ๋ ค๋ ์์ ์ด ๊ฐ์ฅ ๋ฆ๊ฒ ์ฒ๋ฆฌ๋๋๋ก ํ๋ค.
'Frontend > React.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
CSR๊ณผ SSR, SSG (0) | 2023.05.07 |
---|---|
React ์ฌ์ฉํ๊ธฐ (0) | 2023.05.01 |