1. Automatic Batching
- ์๋ ๋ฐฐ์น๋ ์ฌ๋ฌ ๊ฐ์ state ์ ๋ฐ์ดํธ๋ฅผ ํ๋๋ก ๋ฌถ์ด render ํจ์๋ฅผ ํธ์ถ(๋ฆฌ๋ ๋๋ง ์ฑ๋ฅ ๊ฐ์ )ํ๋ ๊ฒ์ ๋งํฉ๋๋ค.
- ๊ธฐ์กด 17 ๋ฒ์ ์์๋ ์ด๋ฌํ ๋ฐฐ์นญ ์ฒ๋ฆฌ๋ ๋์์ง๋ง ๋น๋๊ธฐ ๋ถ๋ถ์์๋ ์๋ ๋ฐฐ์น ์ฒ๋ฆฌ๊ฐ ๋์ง ์์์ต๋๋ค. ํ์ง๋ง 18 ๋ฒ์ ๋ถํฐ๋ ๋น๋๊ธฐ์์๋ ์๋ ๋ฐฐ์น ์ฒ๋ฆฌ๋ฅผ ์ง์ํฉ๋๋ค.
import { useState } from "react";
import "./App.css";
function App() {
const [number, setNumber] = useState(0);
const [boolean, setBoolean] = useState(true);
const onClick = () => {
setNumber((prev) => prev + 1);
setBoolean(!boolean);
};
console.log("๋ ๋๋ง");
return (
<div className="App">
<h1>{number}</h1>
<h2>{boolean.toString()}</h2>
<button onClick={onClick}>๋ฒํผ</button>
</div>
);
}
export default App;
์ ์์ค๋ ์๋ ํ๋ฉด์ ๋ํ๋ ๋๋ค.
์ ํ๋ฉด์ ์ด๊ธฐ์ ํ๋ฉด์ด ์ถ๋ ฅ๋ ๋ ๋ ๋๋ง์ด ์ฝ์์ ์ฐํ๋๋ค.
์์ ๊ฐ์ด ๋ฒํผ์ ํด๋ฆญํ๋ฉด onClickํจ์๊ฐ ํธ์ถ๋๊ณ setNumber์ setBoolean์ ์ํ ๋ณ๊ฒฝ์ ํ๋๋ก ๋ฌถ์ด ๋ฆฌ๋ ๋๋ง์ ํ ๋ฒ๋ง ์ํํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ฌ๊ธฐ๊น์ง๋ ๋ฒ์ 17๊ณผ ๊ฐ์ต๋๋ค.
๋น๋๊ธฐ์์ ์๋๋ฐฐ์น
- ๊ธฐ์กด 17 ๋ฒ์ ์ ๋น๋๊ธฐ์์ ์๋ ๋ฐฐ์น๋ฅผ ์ง์ํ์ง ์์์ง๋ง 18 ๋ฒ์ ์์๋ ๋น๋๊ธฐ์์๋ ์๋ ๋ฐฐ์น๋ฅผ ์ง์ํฉ๋๋ค.
์๋๋ ๋น๋๊ธฐ์์ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ๋ ์์ค์ฝ๋์ ๋๋ค.
import { useState } from "react";
import "./App.css";
function App() {
const [number, setNumber] = useState(0);
const [boolean, setBoolean] = useState(true);
const onClick = () => {
setTimeout(() => {
setNumber((prev) => prev + 1);
setBoolean(!boolean);
}, 2000);
};
console.log("๋ ๋๋ง");
return (
<div className="App">
<h1>{number}</h1>
<h2>{boolean.toString()}</h2>
<button onClick={onClick}>๋ฒํผ</button>
</div>
);
}
export default App;
์๋ ํ๋ฉด๊ณผ ๊ฐ์ด 18 ๋ฒ์ ์ ๋น๋๊ธฐ์์๋ ์๋ ๋ฐฐ์น๋ฅผ ์ง์ํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์๋์ ๊ฐ์ด ํ๋๋ ๋๊ธฐ์ ์ํ ์ ๋ฐ์ดํธ์ ๋น๋๊ธฐ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ์งํํ ๊ฒฝ์ฐ๋ ์ด๋ป๊ฒ ๋ ๊น?
import { useState } from "react";
import "./App.css";
function App() {
const [number, setNumber] = useState(0);
const [boolean, setBoolean] = useState(true);
const onClick = () => {
setTimeout(() => {
setNumber((prev) => prev + 1);
}, 2000);
setBoolean(!boolean);
};
console.log("๋ ๋๋ง");
return (
<div className="App">
<h1>{number}</h1>
<h2>{boolean.toString()}</h2>
<button onClick={onClick}>๋ฒํผ</button>
</div>
);
}
export default App;
์๋์ ๊ฐ์ด ๋น๋๊ธฐ์์ ์ํ ์ ๋ฐ์ดํธ์ ์ผ๋ฐ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ๋ฐ๋ก ๋ฆฌ๋ ๋๋ง ํฉ๋๋ค.
setTimeout ์์์ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ํ๋๋ก ๊ทธ๋ฃนํํ๊ณ onClick ํจ์์ setTimeout ๋ฐ์์์ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ๊ทธ๋ฃนํํฉ๋๋ค.
๋ง์ฝ ์๋ ๋ฐฐ์น ์ฒ๋ฆฌ๋ฅผ ์ํ์ง ์๋๋ค๋ฉด?
- react-dom์ flushSync์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์๋์ ๊ฐ์ด flushSync๋ฅผ ํ์ฉํ์ฌ ์ํ ์ ๋ฐ์ดํธํ๋ฉด ์๋ ๋ฐฐ์นญ ์ฒ๋ฆฌ๊ฐ ๋์ง ์์ต๋๋ค.
import { useState } from "react";
import { flushSync } from "react-dom";
import "./App.css";
function App() {
const [number, setNumber] = useState(0);
const [boolean, setBoolean] = useState(true);
const onClick = () => {
flushSync(() => {
setNumber((prev) => prev + 1);
});
flushSync(() => {
setBoolean(!boolean);
});
};
console.log("๋ ๋๋ง");
return (
<div className="App">
<h1>{number}</h1>
<h2>{boolean.toString()}</h2>
<button onClick={onClick}>๋ฒํผ</button>
</div>
);
}
export default App;
์๋ ํ๋ฉด๊ณผ ๊ฐ์ด ์๋ ๋ฐฐ์น๊ฐ ์ ์ฉ๋์ง ์์ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
2. useTranstion
- ๊ฐ ์ํ ์ ๋ฐ์ดํธ์ ๋ํ ์ฐ์ ์์๋ฅผ ์ค์ ํ ์ ์๋ hook์ ๋๋ค.
- isPending: boolean ์ state๋ณ๊ฒฝ ์งํ์๋ ๋ฆฌ๋ ๋๋ง ํ์ง ์๊ณ UI๋ฅผ ์ ์ ์ ์งํ๋ ์ํ์ ๋๋ค.
- startTransition์ ํด๋ฆญ์ด๋ ํค ์ ๋ ฅ์ ์ํด ์ฐ์ ์์๊ฐ ๋์ ์ํ ์ ๋ฐ์ดํธ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ ๋ด๋ถ์ ์ ์ธํ ์ํ ์ ๋ฐ์ดํธ๋ ์ค๋จ๋๊ณ ํด๋ฆญ์ด๋ ํค ์ ๋ ฅ์ด ๋๋ ํ ์ดํ์ ํด๋น ์ํ ์ ๋ฐ์ดํธ๊ฐ ๋ฐ์ํฉ๋๋ค.
์ธ์ ์ฌ์ฉํ ๊น?
ํ๋ฒ ๋ ๋๋ง ์ฐ์ฐ์ด ์์๋๋ฉด ๋ฉ์ถ ์๊ฐ ์๋ ๋ธ๋กํน ๋ ๋๋ง ๋ฌธ์ ๋ฅผ ๊ฐ์ ํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ ์ ๋ ฅ์ฐฝ์ ๊ฒ์์ด๋ฅผ ์ ๋ ฅํ ๋ ์ ๋ ฅ๊ณผ ํจ๊ป ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ์ฃผ๋ ๊ฒฝ์ฐ ์ฌ์ฉ์๊ฐ ์ ๋ ฅ์ ํ๊ณ ์์์๋ ๋ ๋๋ง ์ฐ์ฐ์ด ์์๋๋ฉด ๋ฉ์ถ ์ ์์ด ์ ๋ ฅ์ฐฝ์ด ๋ฒ๋ฒ ๊ฑฐ๋ฆฌ๋ ํ์์ด ๋ํ๋ ์ฌ์ฉ์ ๊ฒฝํ์ด ์ข์ง ์๊ฒ ๋ฉ๋๋ค.
์๋์ ๊ฐ์ด ๊ธด๊ธ ์ ๋ฐ์ดํธ์ ์ ํ ์ ๋ฐ์ดํธ๊ฐ ์๋ค๋ฉด ์ ํ ์ ๋ฐ์ดํธ ๋๋ฌธ์ ๊ธด๊ธ ์ ๋ฐ์ดํธ๊ฐ ๋ฐฉํด๋์ด ๋ธ๋กํน ๋ ๋๋ง ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ๊ธด๊ธ ์ ๋ฐ์ดํธ: ์ ๋ ฅ, ํด๋ฆญ, ๋๋ฅด๊ธฐ์ ๊ฐ์ ์ฌ์ฉ์๊ฐ ์ง์ ์ ์ธ ์ํธ ์์ฉ
- ์ ํ ์ ๋ฐ์ดํธ: UI ์ ํ
์ด์ ๋ฒ์ ์์๋ ๊ฒ์ ๊ฒฐ๊ณผ ๋ฑ์์ ์ฌ์ฉํ๋ Debounce, Throttle ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ์ผ์ ์๊ฐ์ ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์์ต๋๋ค.
Debounce์ Throttle์ ๊ฒฝ์ฐ ์ผ์ ์๊ฐ์ ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ์ผ๋ก ๋ฌธ์ ๋ฅผ ์ ์ ๋ฏธ๋ฃจ๋ ๋ฐฉ์์ด์๋ค๋ฉด startTranstion์ ์ฌ์ฉํด์ ํ๋ฉด์ ๊ทธ๋ฆฌ๋ ์ฐ์ ์์๋ฅผ ๋ฎ์ถ๊ณ ์ฌ์ฉ์ ์ ๋ ฅ์ ์ฐ์ ์์๋ฅผ ๋์ฌ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์ํ ์ ์์ต๋๋ค. ์ฆ ๊ธด๊ธ ์ ๋ฐ์ดํธ๋ฅผ ์ ํ ์ ๋ฐ์ดํธ๋ณด๋ค ์ฐ์ ์์๋ฅผ ๋๊ฒ ์ค์ ํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฒ์ ๋๋ค.
Debounce
- ์ ๋ ฅ์ด ๋ค ๋๋๋ฉด ์ผ์ ์๊ฐ ๋ค ํ๋ฉด ์ ๋ฐ์ดํธ๋ฅผ ํ ์ ์์ต๋๋ค.
- ์ ๋ ฅํ๋ ๋์ ํ๋ฉด์ ๊ทธ๋ฆฌ์ง ์๊ฒ ํฉ๋๋ค.
throttle
- ์ผ์ ํ ์ฃผ๊ธฐ๋ก ํ๋ฉด์ ๊ทธ๋ฆฌ๊ฒ ํ๋ค
- ์ฌ์ฉ์๊ฐ ์ผ์ ์ฃผ๊ธฐ ๋์ ์ ๋ ฅ์ ํ์ง ์์ ๊ฒฝ์ฐ์๋ ๊ธฐ๋ค๋ ค์ผ ํ๋ค.
startTransition
- ํ๋ฉด ์ ๋ฐ์ดํธ ์ค์๋ ์ฌ์ฉ์ ์ ๋ ฅ์ ๋ฐ์ ์ ์์ต๋๋ค.
- ๋ ๋๋ง ํ๋ ์์ค์๋ ์ฐ์ ์์๊ฐ ๋์ ์ผ์ด ์๊ธฐ๋ฉด ๊ทธ๊ฒ์ ๋จผ์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- timeountMS ์ค์ ํ๋ฉด ํด๋น ์๊ฐ ๋์ ๋ ๋๋ง์ ๊ธฐ๋ค๋ค๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ง ๋ชปํ๋ฉด ๊ฐ์ ๋ก ๋ ๋๋ง ๋ฉ๋๋ค.
์๋๋ useTrasition์ ๊ตฌํํ ์์ค์ ๋๋ค.
import { useState, useTransition } from "react";
import "./App.css";
function App() {
const [isPending, startTransition] = useTransition({ timeoutMs: 5000 });
const [keyword, setKeyword] = useState("");
const [list, setList] = useState([]);
const onChange = (e) => {
setKeyword(e.target.value); // ๊ธด๊ธ ์
๋ฐ์ดํธ
startTransition(() => {
// ์ ํ ์
๋ฐ์ดํธ
setList([...Array(e.target.value.length * 1000)]);
});
};
return (
<div className="App">
<input type={"text"} value={keyword} onChange={onChange} />
<div>
{isPending && <p>...isPending</p>}
{list.map((el, i) => {
return (
<div
key={i}
style={{
width: 100,
height: 100,
margin: 3,
backgroundColor: "black",
}}
></div>
);
})}
</div>
</div>
);
}
export default App;
3. Suspense and SSR
์๋ฒ์ฌ์ด๋ ๋ ๋๋ง์ ๊ฒฝ์ฐ ์๋ฒ์ ๋ฐ์ดํฐ๊ฐ ๋ชจ๋ ์ฑ์์ง html ๋ฆฌ์์ค๋ฅผ ๋ฐ์ ๋ ๋๋งํ๊ณ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ๋ก๋ฉ ํ Hydration ๋จ๊ณ๋ก ๋์ด๊ฐ๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๋ก๋ฉํ๊ธฐ ์ ์๋ Hydration(์๋ฐ์คํฌ๋ฆฝํธ ์ฐ๊ฒฐ) ๋จ๊ณ๋ก ๋์ด๊ฐ ์ ์๊ณ ์ฌ์ฉ์๊ฐ ์ฑ๊ณผ ์ํธ ์์ฉํ๊ธฐ ์ํด์๋ Hydration ๋จ๊ณ๊น์ง ์๋ฃ๋์ด์ผ ํฉ๋๋ค.
์ด์ ๊ฐ์ ๋ฌธ์ ๋ฅผ Suspense์ lazy๋ฅผ ์ฌ์ฉํ์ฌ ๋ ๋๋ง ์ฑ๋ฅ์ ํฅ์ํ ์ ์์ต๋๋ค.
lazy & Suspense
๋ชจ๋ ๋ฐ์ดํฐ๊ฐ fetch ๋์ด์ผ ๋ ๋ ํ ์ ์์ง๋ง Suspense์ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ธ๋ฉด ํด๋น ์ปดํฌ๋ํธ์ ๋ฐ์ดํฐ๊ฐ ์ค๋น๋ ๋๊น์ง fallback์ผ๋ก ์์ง ์ฒ๋ฆฌ๋์ง ์์์ ๋์ ์ปดํฌ๋ํธ(์: loading spinner)๋ฅผ ํ๋ฉด์ ํ์ํ๊ณ ๋ฐ์ดํฐ๊ฐ fetch ๋ ๋ค๋ฅธ ์ปดํฌ๋ํธ ๋ถ๋ถ๋ถํฐ ๋ณด์ฌ์ค ์ ์์ต๋๋ค. lazy & Suspense๋ฅผ ํ์ฉํด ๊ตฌํํ ๊ฒฝ์ฐ ํด๋น ์ปดํฌ๋ํธ๊ฐ ์์ง ๋ ๋๋ง ๋์ง ์์์ด๋ ์๊ด์์ด ๋ค๋ฅธ ์ปดํฌ๋ํธ๋ค์ hydration์ ์์ํ ์ ์๊ฒ ๋์์ต๋๋ค.
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
'Frontend' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋ฐ๋ฒจ(Babel) ์ค์ ํ๊ธฐ (0) | 2022.10.31 |
---|---|
React-Query (1) | 2022.10.11 |
CRA(Create React App) ์นํฉ ์ค์ ํ๊ธฐ (2) | 2022.09.20 |
React์์ setInterval ์ฌ์ฉํ๊ธฐ (0) | 2022.07.28 |
TDD (ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ) (0) | 2022.06.23 |