2024-04-13.md
๐กDIL: ๋ชจ๋ ๋ฆฌ์กํธ ๋ฅ ๋ค์ด๋ธ, 6์ฃผ์ฐจ-6
์คํฐ๋: ์๊ฐ CS, https://github.com/monthly-cs/2024-03-modern-react-deep-dive
์ค๋ ์งํ: ๊ฐ์ธ๊ณต๋ถ
DIL-week6-6_2024-04-13
| DIL ์ฃผ์ฐจ | ๋ฒ์ | ๋ด์ฉ | ์ค๋์ฐจ ์ง๋ | | -------- | ---------- | --------------------------------------------------------- | ----------- | | 6์ฃผ์ฐจ | 10์ฅ, 11์ฅ | ๋ฆฌ์กํธ 17๊ณผ 18 ๋ณ๊ฒฝ ์ฌํญ ์ดํด๋ณด๊ธฐ, Next.js 13๊ณผ ๋ฆฌ์กํธ 18 | p~ |
์ค๋ ์ฝ์ ๋ด์ฉ์ markdown์ผ๋ก ๊ฐ๋จํ ๋ฉ๋ชจ
React 18
react-dom/client
- ํด๋ผ์ด์ธํธ์์ ๋ฆฌ์กํธ ํธ๋ฆฌ๋ฅผ ๋ง๋ค ๋ ์ฌ์ฉํ๋ API ๋ณ๊ฒฝ์
- index.{t|j}sx ๋ด์ฉ ๋ณ๊ฒฝ
createRoot
- render => createRoot + render
const root = ReactDOM.createRoot(container);
root.render(<App />);
hydrateRoot
- ์๋ฒ ์ฌ์ด๋ ๋๋๋ง ์ ํ๋ฆฌ์ผ์ด์
์์ ํ์ด๋๋ ์ด์
์ ํ๊ธฐ ์ํ ๋ฉ์๋
- ํ๋ ์์ํฌ์ ์์กดํ๊ณ ์์ ๊ฒ์ด๋ฏ๋ก ์์ ํ ์ผ์ด ๊ฑฐ์ ์๋ค.
// before
import ReactDOM from "react-dom";
import App from "App";
const container = document.getElementById("root");
ReactDOM.hydrate(<App />, container);
// 18
const root = ReactDOM.hydrateRoot(container, <App />);
onRecoverableError
- createRoot, hydrateRoot์ ์ต์
- ๊ณผ์ ์์ ์๋ฌ๊ฐ ๋ฐ์ํ์ ๋ ๋ฐ์ํ๋ ์ฝ๋ฐฑ ํจ์ => reportError, console.error ๋๋ ์ํ๋ ๋ด์ฉ ์ถ๊ฐ
react-dom/server
renderToPipeableStream
- ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ฅผ HTML๋ก ๋๋๋งํ๋ ๋ฉ์๋, ์คํธ๋ฆผ์ ์ง์
- HTML์ ์ ์ง์ ์ผ๋ก ๋๋๋ง, ํด๋ผ์ด์ธํธ๋ ์ค๊ฐ์ script๋ฅผ ์ฝ์
ํ๋ ๋ฑ์ ์์
์ ํ ์ ์์
- ์๋ฒ์์ Suspence๋ฅผ ์ฌ์ฉํด, ๋น ๋ฅด๊ฒ ๋๋๋ง ํ์ํ ๋ถ๋ถ ๋๋๋ง(๋น์ผ ์ฐ์ฐ ๋์ค์)
- ์ฒซ ๋ฒ์งธ ๋ก๋ฉ์ ๋น ๋ฅด๊ฒ ์ํํ๊ธฐ
- hydrateRoot๋ฅผ ํธ์ถํด ์๋ฒ์์๋ HTML ๋๋๋ง + ํด๋ผ์ด์ธํธ์ ๋ฆฌ์กํธ์๋ ์ด๋ฒคํธ๋ง ์ถ๊ฐ
- ๊ธฐ์กด renderToNodeStream ๋ฌธ์ ์ -> ๋ฌด์กฐ๊ฑด ์์๋๋ก, ์์์ ์์กด์ / ๋ธ๋ฝํน, ๋ณ๋ชฉ
- ์ ๊ฐ์ ์ฝ๋ ๋ถํ , ์ง์ฐ ๋๋๋ง์ ์๋ฒ์ฌ์ด๋์์ ์ฌ์ฉ
- ์ค์ ๋ก ํ๋ ์์ํฌ๊ฐ ์๋๋ผ renderToPipableStream์ผ๋ก ์๋ฒ์ฌ์ด๋ ๋๋๋ง์ ๋ง๋๋ ๊ฒฝ์ฐ ๊ฑฐ์ ์์ง๋ง -> ์ฌ์ฉํ๋ ํ๋ ์์ํฌ์์ ๋ฆฌ์กํธ 18์ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด? ๋ฉ์๋ ์ง์ ์ฌ๋ถ ํ์ธ ํ์
renderToReadableStream
- ์น ์คํธ๋ฆผ์ ์ฌ์ฉํ๋ ๋ชจ๋ ์ฃ์ง ๋ฐํ์ ํ๊ฒฝ์์ ์ฌ์ฉํ๋ ๋ฉ์๋ (์ผ๋ฐ์ ์ผ๋ก๋ ์ฌ์ฉ x)
- renderToPipeableStream: Node.js
- renderToReadableStream: web stream
์๋ ๋ฐฐ์น Automatic Batching
- ๋ฆฌ์กํธ๊ฐ ์ฌ๋ฌ ์ํ๋ฅผ ํ๋์ ๋ฆฌ๋๋๋ง์ผ๋ก ๋ฌถ์ด์ ์ฑ๋ฅ์ ํฅ์์ํค๋ ๋ฐฉ๋ฒ
- ์ฌ์ฉ์ ์ก์ ์ด ํ ๋ฒ์ ๋ ๊ฐ ์ด์์ state์ ๋์์ ์ ๋ฐ์ดํธ ํ๋ค? -> ํ๋์ ๋ฆฌ๋๋๋ง์ผ๋ก ๋ฌถ์ด์ ์ํ
- Promise, setTimeout๊ณผ ๊ฐ์ ๋น๋๊ธฐ ์ด๋ฒคํธ
- 17์ ๊ฒฝ์ฐ? ๋ ๋ฒ ๋ฆฌ๋๋๋ง, 18์์๋ ์๋ ๋ฐฐ์น๋ก ํ ๋ฒ ๋ฆฌ๋๋๋ง(๋ชจ๋ ์ ๋ฐ์ดํธ๊ฐ ๋ฐฐ์น ์์ ์ผ๋ก ์ต์ ํ๋๋๋ก ๋ฐ๋)
- ๊ทธ ์ธ์ ์ด๋ฒคํธ๋ ๋์ผํ๊ฒ 1๋ฒ
- ์๋ ๋ฐฐ์น๋ฅผ ์ํ ๊ฒฝ์ฐ > flushSync๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
๋ฌธ์์ด ref ์ฌ์ฉ ๊ธ์ง
<input type="text" ref="myInput" />; // ๋ฌธ์์ด์ ref๋ก ์ฌ์ฉํจ
console.log(this.refs.myInput); // deprecated
- ๋ฌธ์ ์
- ์ฌ๋ฌ ์ปดํฌ๋ํธ์ ๊ฑธ์ณ ์ฌ์ฉ๋ ์ ์์ผ๋ฏ๋ก ์ถฉ๋์ ์ฌ์ง ์์
- ๋จ์ ๋ง์์ด๋ก ์กด์ฌํ๊ธฐ ๋๋ฌธ์, ์ด๋ค ref์์ ์ฐธ์กฐ๋๊ณ ์๋ ์ง ํ์ ํ๊ธฐ ์ด๋ ค์
- ๋ฆฌ์กํธ๊ฐ ๊ณ์ํด์ ํ์ฌ ๋๋๋ง๋๊ณ ์๋ ์ปดํฌ๋ํธ์ ref ๊ฐ์ ์ถ์ ํ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ ์ด์๊ฐ ์์
findDOMNode์ ๋ํ ๊ฒฝ๊ณ
- ํด๋์ค ์ปดํฌ๋ํธ ์ธ์คํด์ค์์ ์ค์ DOM ์์์ ๋ํ ์ฐธ์กฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ ์ง๊ธ์ ๊ถ์ฅ๋์ง ์๋ ๋ฉ์๋
- ๋ถ๋ชจ๊ฐ ํน์ ์์๋ง ๋ณ๋๋ก ๋๋๋งํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ค. ๋ฆฌ์กํธ๊ฐ ์ถ๊ตฌํ๋ ํธ๋ฆฌ ์ถ์ํ ๊ตฌ์กฐ์ ๋ง์ง ์์
๊ตฌ Context API ์ฌ์ฉ ์ ๊ฒฝ๊ณ
- (์๊ฒฉ ๋ชจ๋) childContextType, getChildContext ์ฌ์ฉ ์ ๊ฒฝ๊ณ
์์์น ๋ชปํ side-effects ๊ฒ์ฌ
- (์๊ฒฉ ๋ชจ๋) ๋ค์์ ์ด์ค ํธ์ถ
- ํด๋์ค ์ปดํฌ๋ํธ์ constructor.render, shoudComponentUpdate.getDerivedStateFromProps
- ํด๋์ค ์ปดํฌ๋ํธ์ setState์ ์ฒซ ๋ฒ์งธ ์ธ์
- ํจ์ ์ปดํฌ๋ํธ์ body
- useState, useMemo, useReducer์ ์ ๋ฌ๋๋ ํจ์
- ์?
- ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์์น์ ๋ฐ๋ผ ๋ชจ๋ ์ปดํฌ๋ํธ๋ ํญ์ ์์ํ๋ค.
- ์ ๋ง ์์ํ ๊ฒฐ๊ณผ๋ฌผ์ ๋ด๊ณ ์๋์ง ๊ฐ๋ฐ์์๊ฒ ํ์ธ ์์ผ์ฃผ๊ธฐ ์ํด ๋ ๋ฒ ์คํํ๋ค.
- ์
๋ ฅ ๊ฐ์ด ๋ณ๊ฒฝ๋์ง ์์ผ๋ฉด, ํญ์ ๊ฐ์ ๊ฒฐ๊ณผ๋ฌผ์ ๋ฐํํ๋ค.
- ์ฆ, state, props, context๊ฐ ๋ณ๊ฒฝ๋์ง ์์ผ๋ฉด? ํญ์ ๋์ผํ JSX๋ฅผ ๋ฐํํด์ผ ํ๋ค.
- ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์์น์ ๋ฐ๋ผ ๋ชจ๋ ์ปดํฌ๋ํธ๋ ํญ์ ์์ํ๋ค.
- console
- 17์์๋ ๋ ๋ฒ log ์ํจ
- 18์์๋ ๋ ๋ฒ์งธ๋ ๊ธ์์์ ํ์
์๊ฒฉ ๋ชจ๋ ์ถ๊ฐ์
- https://react.dev/blog/2022/03/08/react-18-upgrade-guide#updates-to-strict-mode
In the future, weโd like to add a feature that allows React to add and remove sections of the UI while preserving state. For example, when a user tabs away from a screen and back, React should be able to immediately show the previous screen. To do this, React would unmount and remount trees using the same component state as before.
- ํฅํ ๋ฆฌ์กํธ์์, ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋ ์ํ์์ ๋ด๋ถ์ ์ํ๊ฐ์ ์ ์งํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ ์์ <- ์ด๊ฑฐ ํฐ ์ผ์
- ex) ๋ค๋ก ๊ฐ๊ธฐ ํ ๋์์์ ๋ ์ด์ ์ํ ์ ์ง
- ์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ง์ดํธ๋ ๋๋ง๋ค, ๋ชจ๋ ์ปดํฌ๋ํธ๋ฅผ ์๋์ผ๋ก ๋ง์ดํธ ํด์ ๋ฐ ์ฌ๋ง์ดํธํด, ๋ ๋ฒ์งธ ๋ง์ดํธ ์ด์ ์ํ๋ก ๋ณต์ํ๋ค.
* React mounts the component. * Layout effects are created. * Effect effects are created. * React simulates unmounting the component. * Layout effects are destroyed. * Effects are destroyed. * React simulates mounting the component with the previous state. * Layout effect setup code runs * Effect setup code runs
Suspense ๊ธฐ๋ฅ ๊ฐํ
- Suspense๋? 16.6์์ ์คํ ๋ฒ์ ์ผ๋ก ๋์
/ ์ปดํฌ๋ํธ ๋์ ์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์๊ฒ ๋์์ฃผ๋ ๊ธฐ๋ฅ
- lazy์ Suspense๋ ํ ์์ผ๋ก ์ฌ์ฉ๋๊ณ , ์ ํ๋ฆฌ์ผ์ด์ ์์ ์๋์ ์ผ๋ก ์ค์ํ์ง ์์ ์ปดํฌ๋ํธ ๋ถํ => ์ด๊ธฐ ๋ ๋๋ง ์๋๋ฅผ ํฅ์์ํด
const DynamicSampleComponent = lazy(() => import("./SampleComponent"));
export default function App() {
return (
<Suspense fallback={<>...loading</>}>
<DynamicSampleComponent />
</Suspense>
);
}
- Next.js์์ Suspense๋ฅผ ์ฌ์ฉํ ๋, ์ง์ฐ ์ค์ธ ์ปดํฌ๋ํธ๋ฅผ ๋๋๋ง ํ ์ ์๊ธฐ ๋๋ฌธ์ useEffect๋ฅผ ํ์ฉํ ์ปค์คํ ํ ๋ฑ์ ๋ง๋ค์ด์ ํด๋ผ์ด์ธํธ์์๋ง ์๋ํ๋๋ก ์ฒ๋ฆฌํ์๋ค.
- ๋ฆฌ์กํธ 18
- ๋ง์ดํธ ๋๊ธฐ ์ง์ ์ effect๊ฐ ๋น ๋ฅด๊ฒ ์คํ๋๋ ๋ฌธ์ ์์ ๋จ. => ์ปดํฌ๋ํธ๊ฐ ์ค์ ๋ก ํ๋ฉด์ ๋ ธ์ถ๋ ๋ effect๊ฐ ์คํ๋๋ค
- Supense๋ก ์ธํด ์ปดํฌ๋ํธ๊ฐ ๋ณด์ด๊ฑฐ๋ ์ฌ๋ผ์ง ๋๋ effect๊ฐ ์ ์์ ์ผ๋ก ์คํ. ์ด์ ์๋ ์ปดํฌ๋ํธ ์ค์ค๋ก๊ฐ Suspense์ ์ํด ํ์ฌ ๋ณด์ฌ์ง๊ณ ์๋์ง ์จ๊ฒจ์ ธ ์๋์ง ์ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์๋ค.
- ์ด์ ? useLayoutEffect์ effect์ cleanUp์ด ์ ์์ ์ผ๋ก ์คํ๋๋ค.
- effect(componentDidMount)
- cleanUp(componentWillUnmount)
- Suspense๋ฅผ ์๋ฒ์์๋ ์คํํ ์ ์์.
- Suspense์ ์ฐ๋กํ๋ง์ด ์ถ๊ฐ๋์๋คํจ. ์ค์ฒฉ๋ Suspense์ fallback์ด ์๋ค๋ฉด ์๋์ผ๋ก throttle ๋๋ค
- ์๊ฑฐ ๋์จ๋ค ํ๋ค. https://codesandbox.io/p/sandbox/sparkling-butterfly-s9zlw3?file=%2FAlbums.js%3A24%2C24
ํ์ธํ ๊ฒ
- Suspense์ ์ฐ๋กํ๋ง์ด ์ถ๊ฐ๋์๋คํจ. ์ค์ฒฉ๋ Suspense์ fallback์ด ์๋ค๋ฉด ์๋์ผ๋ก throttle ๋๋ค