2024-03-16.md
๐กDIL: ๋ชจ๋ ๋ฆฌ์กํธ ๋ฅ ๋ค์ด๋ธ, 2์ฃผ์ฐจ-5
์คํฐ๋: ์๊ฐ CS, https://github.com/monthly-cs/2024-03-modern-react-deep-dive
์ค๋ ์งํ: ๊ฐ์ธ๊ณต๋ถ
DIL-week2-5_2024-03-16
| DIL ์ฃผ์ฐจ | ๋ฒ์ | ๋ด์ฉ | ์ค๋์ฐจ ์ง๋ | | -------- | ------ | ------------------------------- | ---------------------------- | | 2์ฃผ์ฐจ | 3, 5์ฅ | ๋ฆฌ์กํธ ํ ๊ณผ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ | 229~251p(22p), 336~399p(63p) |
์ค๋ ์ฝ์ ๋ด์ฉ์ markdown์ผ๋ก ๊ฐ๋จํ ๋ฉ๋ชจ
์ฝ์ ์๊ฐ: 9~21์๋ฐ (์ค๊ฐ์ค๊ฐ ํด์)
ํ ์์ผ ๋ค๋ฅธ ์ผ์ x, ์ฑ ์ฝ๊ธฐ
reference
- What is tearing? https://github.com/reactwg/react-18/discussions/69
๐ React Hook ํํค์น๊ธฐ
useImperativeHandle
- ์ค๋ฌด์์ ์์ฃผ ๋ณผ ์ ์์
- ์ผ๋ถ ์ฌ๋ก์์ ์ ์ฉ
React.forwardRef
- ref๋ useRef์์ ๋ฐํํ ๊ฐ์ฒด, ๋ฆฌ์กํธ ์ปดํฌ๋ํธ์ props์ธ ref์ ๋ฃ์ด HTMLElement์ ์ ๊ทผํ๋ ์ฉ๋๋ก ํํ ์ฌ์ฉ
- ref๋ ๋ฆฌ์กํธ์์ ์ปดํฌ๋ํธ์ props๋ก ์ฌ์ฉํ ์ ์๋ ์์ฝ์ด ex)
key
- ref๋ฅผ ์์ ์ปดํฌ๋ํธ์์ ํ์ ์ปดํฌ๋ํธ๋ก ์ ๋ฌํ๊ณ ์ถ๋ค๋ฉด?
Error:
ref
is not a prop. Trying to access it will result inundefined
being returned. If you need to access the same value within the child component, you should pass it as a different prop. - ๋ค๋ฅธ props๋ก ๋ฐ์ผ๋ฉด ์๋
- ๊ฐ์ ์์ ์ ํ๋ ๋ฆฌ์กํธ API > forwardRef
- ์ผ๊ด์ฑ
useImperativeHandle
- ๋ถ๋ชจ์๊ฒ์ ๋๊ฒจ๋ฐ์ ref๋ฅผ ์ํ๋ ๋๋ก ์์ ํ ์ ์๋ ํ
const Input = forwardRef((props, ref) => {
// useImperativeHandle: ref์ ๋์์ ์ถ๊ฐ๋ก ์ ์
useImperativeHandle(
ref, // ref
() => ({
// ref.current๋ฅผ ๋ฎ์ด์
alert: () => alert(props.value), // ์ํ๋ ๊ฐ์ด๋ ๋์
foo: "bar",
// ...ref, // ref๋ undefined
}),
[props.value] // ์์กด์ฑ ๋ฐฐ์ด
);
return <input ref={ref} {...props} />;
});
- ref ํ์ธ
function handleClick() {
inputRef.current?.alert(); // ์๋กญ๊ฒ ์ ์ํ ๋์์ ์คํํ์
console.log(inputRef.current); // {foo: 'bar', alert: ฦ}
console.log(inputRef.current.value); // undefined
inputRef.current?.ref; // ์๋กญ๊ฒ ์ ์ํ ref์ ๊ธฐ์กด ref๋ฅผ ๋ฃ์ผ๋ ค ํ์ผ๋ ์ญ์ undefined
}
useLayoutEffect
- ๋ชจ๋ DOM์ ๋ณ๊ฒฝ(๋ฆฌ์กํธ ๋๋๋ง) ํ, ๋๊ธฐ์ ์ผ๋ก ๋ฐ์ํ๋ค
- ๋ฆฌ์กํธ๊ฐ DOM์ ์ ๋ฐ์ดํธ
- useLayoutEffect
- ๋ธ๋ผ์ฐ์ ์ ๋ฐ์
- useEffect
- useLayoutEffect์ ๋ธ๋ผ์ฐ์ ์ ๋ณ๊ฒฝ์ฌํญ์ด ๋ฐ์๋๊ธฐ ์ ์ ๋๊ธฐ์ ์ผ๋ก ์คํ
- ์คํ์ด ์ข ๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ ๋ค์ ํ๋ฉด์ ๊ทธ๋ฆฐ๋ค
- ์ปดํฌ๋ํธ ์ผ์ ์ค์ง: ์ฑ๋ฅ ๋ฌธ์
- DOM์ ๊ณ์ฐ๋์ง๋ง ์ด๊ฒ์ด ํ๋ฉด์ ๋ฐ์๋๊ธฐ ์ ์ ํ๊ณ ์ถ์ ์์ ์ด ์์ ๋/๋ฐ๋์ ํ์ํ ๋ ex) ์ ๋๋ฉ์ด์ , ์คํฌ๋กค ์์น ์ ์ด
useDebugValue
- ์ผ๋ฐ์ ์ผ๋ก ํ๋ก๋์ x
- ๋๋ฒ๊น
์ ๋ณด -> ๋ฆฌ์กํธ ๊ฐ๋ฐ์ ๋๊ตฌ
- ์ฒซ ๋ฒ์งธ ์ธ์: ๊ฐ
- ๋ ๋ฒ์งธ ์ธ์: ํฌ๋งคํ ํจ์ (์ฒซ ๋ฒ์งธ ์ธ์์ ๊ฐ์ด ๊ฐ์ผ๋ฉด ํธ์ถ๋์ง ์์)
- ๋ค๋ฅธ ํ ๋ด๋ถ์์๋ง ์คํํ ์ ์์
function useDate() {
const date = new Date();
useDebugValue(date, (date) => `ํ์ฌ ์๊ฐ: ${date.toUTCString()}`);
return date;
}
Rules of Hooks
rules-of-hooks
https://legacy.reactjs.org/docs/hooks-rules.html
- ์ต์์์์ ํธ์ถํ๋ค
- ๋ฐ๋ณต๋ฌธ, ์กฐ๊ฑด๋ฌธ, ์ค์ฒฉ ํจ์ ๋ด์์ ์คํํ ์ ์๋ค.
- ์? ์ปดํฌ๋ํธ๊ฐ ๋๋๋ง๋ ๋ ๋์ผํ ์์๋ก ํ ์ ํธ์ถํ๋ ๊ฒ์ ๋ณด์ฅ
- ๋ฆฌ์กํธ ํจ์ ์ปดํฌ๋ํธ, ์ปค์คํ ํ ์์ ํธ์ถํ๋ค
- ์ผ๋ฐ ์๋ฐ์คํฌ๋ฆฝํธ ํจ์์์๋ ํ ์ ์ฌ์ฉํ ์ ์์
- ํ
์ ๋ํ ์ ๋ณด ์ ์ฅ => ๋ฆฌ์กํธ ์ด๋๊ฐ์ index์ ๊ฐ์ ํค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌํ (๋งํฌ๋ ๋ฆฌ์คํธ) - ์์์ ์ํฅ์ ๋ฐ์
- ํ์ด๋ฒ ๊ฐ์ฒด์ ๋งํฌ๋ ๋ฆฌ์คํธ ํธ์ถ ์์
const [count, setCount] = useState(0) // 1๏ธโฃ
const [required, setRequired] = useState(false) // 2๏ธโฃ
useEffect(()=>{ // 3๏ธโฃ
// ...
},[count, required])
// Fiber
{ // 1๏ธโฃ setCount
memoizedState: 0,
baseState: 0,
queue: {/* ... */},
baseUpdate: null,
next: { // 2๏ธโฃ setRequired
memoizedState: false,
baseState: false,
queue: {/* ... */},
baseUpdate: null,
next: { // 3๏ธโฃ useEffect
memoizedState: {
tag: 192,
create: ()=>{},
destroy: undefined,
deps: [0, false], // ์์กด์ฑ ๋ฐฐ์ด ๊ฐ! (์ด์ ๊ฐ๊ณผ ๋น๊ต)
next: {/* ... */}
},
baseState: false,
queue: {/* ... */},
baseUpdate: null,
}
}
}
- ๊ณ ์ ๋ ์์์ ์์กดํด ํ ๊ณผ ๊ด๋ จ๋ ์ ๋ณด๋ฅผ ์ ์ฅํจ = ์ด์ ๊ฐ์ ๋ํ ๋น๊ต์ ์คํ
- ํ ์ ์กฐ๊ฑด๋ฌธ/๋ฐ๋ณต๋ฌธ ๋ฑ์ ์ํด ๋ฆฌ์กํธ์์ ์์ธก ๋ถ๊ฐ๋ฅํ ์์๋ก ์คํ๋๊ฒ ํด์๋ ์ ๋๋ค.
- ๋ฐ๋ผ์ ์คํ ์์๋ฅผ ๋ณด์ฅ๋ฐ์ ์ ์๋ ์ปดํฌ๋ํธ ์ต์๋จ์ ์ ์ธ๋์ด ์์ด์ผ ํ๋ค.
Custom Hook vs Higher order component
- ์ปค์คํ
ํ
- ๋ฆฌ์กํธ ํ
์ ๊ท์น์ ๋ฐ๋ฅด๋ฉด์ ๊ฐ๋ฐ์๊ฐ ์๋ก์ด ํ
๋ง๋ฆ
- ์? ๋ด๋ถ์์ ํ ์ฌ์ฉํด์ผํจ,
- ์ ๋ช
์ปค์คํ
ํ
:
use-Hooks
,react-use
,ahooks
- ๋ฆฌ์กํธ ํ
์ ๊ท์น์ ๋ฐ๋ฅด๋ฉด์ ๊ฐ๋ฐ์๊ฐ ์๋ก์ด ํ
๋ง๋ฆ
- HOC๋ ์ปดํฌ๋ํธ ๋ก์ง ์ฌ์ฌ์ฉ ex) React.memo
HOC
- ์ปดํฌ๋ํธ๋ฅผ ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ก ๊ฐ์ธ์, ์ปค์คํ ํ ๋ณด๋ค ํฐ ์ํฅ๋ ฅ (์ปดํฌ๋ํธ ๊ฒฐ๊ณผ๋ฌผ์ ์ํฅ์ ๋ฏธ์นจ)
- with ์ ๋์ฌ๋ก ์์ํ๋ค (์ผ์ข ์ ๊ฐ๋ฐ์ ์ปจ๋ฒค์ )
- ๋ถ์ํจ๊ณผ๋ฅผ ์ต์ํํ๋ค.
- ์ธ์ ์ปดํฌ๋ํธ์ props๋ฅผ ์์๋ก ์์ , ์ถ๊ฐ, ์ญ์ ํ์ง ์๊ธฐ
๋ถ๋ชจ ์ปดํฌ๋ํธ, ๊ณ ์ฐจ ์ปดํฌ๋ํธ, wrapper ์ปดํฌ๋ํธ์ ์ฐจ์ด์
๋ถ๋ชจ ์ปดํฌ๋ํธ
๋ถ๋ชจ ์ปดํฌ๋ํธ๋ ์์ ์ปดํฌ๋ํธ๋ค์ ํฌํจํ๊ณ , ์์ ์ปดํฌ๋ํธ์๊ฒ props๋ฅผ ํตํด ๋ฐ์ดํฐ๋ ์ฝ๋ฐฑ ํจ์ ๋ฑ์ ์ ๋ฌํ๋ ์ปดํฌ๋ํธ์ ๋๋ค. ๋ถ๋ชจ ์ปดํฌ๋ํธ๋ ์์ ์ปดํฌ๋ํธ์ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ฑฐ๋, ์์ ๊ฐ์ ๋ฐ์ดํฐ ํ๋ฆ์ ์กฐ์ ํ๋ ์ญํ ์ ํ ์ ์์ต๋๋ค. ๋ถ๋ชจ ์ปดํฌ๋ํธ๋ ์ผ๋ฐ์ ์ธ ์ปดํฌ๋ํธ ๊ณ์ธต์์์ ์ํ ๊ด๊ณ๋ฅผ ๋ํ๋ ๋๋ค.
function ParentComponent() {
const message = "Hello from Parent!";
return <ChildComponent message={message} />;
}
๊ณ ์ฐจ ์ปดํฌ๋ํธ (Higher-Order Components, HOC)
๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ ์ปดํฌ๋ํธ๋ฅผ ์ ๋ ฅ์ผ๋ก ๋ฐ์ ์๋ก์ด ์ปดํฌ๋ํธ๋ฅผ ๋ฐํํ๋ ํจ์์ ๋๋ค. HOC๋ ์ฃผ๋ก ๋ก์ง์ ์ฌ์ฌ์ฉ์ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉ๋ฉ๋๋ค. ์ฆ, ์ฌ๋ฌ ์ปดํฌ๋ํธ ๊ฐ์ ๊ณต์ ํ ์ ์๋ ๊ณตํต ๋ก์ง์ด๋ ์ํ ๊ด๋ฆฌ, ์๋ช ์ฃผ๊ธฐ ๋ฉ์๋ ๋ฑ์ HOC๋ก ๋ถ๋ฆฌํ์ฌ ๊ฐ ์ปดํฌ๋ํธ์ ์ ์ฉํ ์ ์์ต๋๋ค.
function withExtraProp(WrappedComponent) {
return function (props) {
return <WrappedComponent extraProp="Extra Prop" {...props} />;
};
}
// ์ฌ์ฉ ์: const EnhancedComponent = withExtraProp(OriginalComponent);
// <EnhancedComponent />
๋ํผ (Wrapper) ์ปดํฌ๋ํธ
๋ํผ ์ปดํฌ๋ํธ๋ ๋ค๋ฅธ ์ปดํฌ๋ํธ๋ค์ ๊ฐ์ธ๋ ์ฉ๋๋ก ์ฌ์ฉ๋๋ ์ปดํฌ๋ํธ์ ๋๋ค. ๋ํผ ์ปดํฌ๋ํธ๋ ์คํ์ผ๋ง, ๋ ์ด์์ ๊ตฌ์ฑ, ์ํ ๊ด๋ฆฌ ๋ฑ์ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ๋ํผ ์ปดํฌ๋ํธ๋ ์ผ๋ฐ์ ์ผ๋ก ์์ ์ปดํฌ๋ํธ์๊ฒ ์ถ๊ฐ์ ์ธ ์์ฑ์ ์ฃผ์ ํ์ง ์๊ณ , ๊ฐ์ธ๋ ์ญํ ์ ์ด์ ์ ๋ง์ถฅ๋๋ค.
function WrapperComponent({ children }) {
return <div className="wrapper">{children}</div>;
}
/** ์ฌ์ฉ ์:
* <WrapperComponent>
* <Component message={message} />
* </WrapperComponent> */
๋น๊ต
| ๊ตฌ๋ถ | ์ธ์ | ๋ชฉ์ | ์ฌ์ฉ ์ฌ๋ก | ์ฌ์ฌ์ฉ์ฑ | | ---------------- | -------------- | ----------------------------------------------------- | -------------------------------------------------- | ------------------------------------------ | | ๋ถ๋ชจ ์ปดํฌ๋ํธ | props | ์์ ๊ณ์ธต์์ ์์ ์ปดํฌ๋ํธ๋ฅผ ๊ด๋ฆฌํ๊ณ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌ | ์ปดํฌ๋ํธ ๊ณ์ธต ๊ตฌ์กฐ ๊ตฌ์ฑ | ๋ฎ์, ์ง์ ์ ์ธ ์์ ๊ด๊ณ ํ์ | | ๊ณ ์ฐจ ์ปดํฌ๋ํธ | ์ปดํฌ๋ํธ | ๋ค๋ฅธ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ธ ์๋ก์ด ์ปดํฌ๋ํธ๋ฅผ ์์ฑ, ์ฌ์ฌ์ฉ์ฑ | ๋ก์ง ์ฌ์ฌ์ฉ, prop ์ฃผ์ , ์กฐ๊ฑด๋ถ ๋๋๋ง, ๊ด์ฌ์ฌ ๋ถ๋ฆฌ | ๋์, ๋ค์ํ ์ปดํฌ๋ํธ์ ์ ์ฉ ๊ฐ๋ฅ | | Wrapper ์ปดํฌ๋ํธ | props.children | ์ถ๊ฐ์ ์ธ ์์ฑ์ ์ฃผ์ ํ์ง ์๊ณ , ๊ฐ์ธ๋ ์ญํ ์ ์ด์ | ์คํ์ผ๋ง, ๋ ์ด์์ ์กฐ์ , ์กฐ๊ฑด๋ถ ๋ํผ | ์ค๊ฐ, ๋น์ทํ ๋ ์ด์์/์คํ์ผ ์๊ตฌ์ ์ฌ์ฌ์ฉ |
custom hook vs HOC
- ๋ญ ์ฐ๋ ๊ฒ ์ข์๊น์ ๊ธฐ์ค
| ๊ตฌ๋ถ | ์ฅ์ | ๋จ์ | ์ฌ์ฉ ์ | | ----------- | ----------------------------------------------------------- | ---------------------------------------------------------------- | -------------- | | custom hook | ๋ถ์ํจ๊ณผ๊ฐ ์ ํ์ , ์ปดํฌ๋ํธ ๋ด๋ถ์ ๋ฏธ์น๋ ์ํฅ์ ์ต์ํ | ๋๋๋ง ๊ฒฐ๊ณผ๋ฌผ์ ์ํฅ์ ๋ฏธ์น ์ ์์, ๋ฐํ๊ฐ์ ๋ฐํ์ผ๋ก ๋ก์ง ์์ฑ | ๋์ผ ๋ก์ง ๊ฒฉ๋ฆฌ | | HOC | ๋๋๋ง ๊ฒฐ๊ณผ๋ฌผ์ ์ํฅ์ ๋ฏธ์นจ, ๋ก์ง์ ๋ฐ๋ผ ๊ณตํต ์ปดํฌ๋ํธ ๋ ธ์ถ | ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ฅผ ์ง์ ๋ณด๊ฑฐ๋ ์คํํ ๋๊น์ง, ๊ฒฐ๊ณผ๋ฌผ์ ์ ์ ์๋ค | ์๋ฌ ๋ฐ์ด๋๋ฆฌ |
๐ ๋ฆฌ์กํธ์ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- ์ํ
- ์ด๋ ํ ์๋ฏธ๋ฅผ ๊ฐ์ง ๊ฐ
- ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋๋ฆฌ์ค์ ๋ฐ๋ผ ์ง์์ ์ผ๋ก ๋ณ๊ฒฝ๋ ์ ์๋ ๊ฐ
- UI, URL, form, API call
์ญ์ฌ ๐จโ๐ฆณ
flux ํจํด
- ๋ฆฌ๋์ค ์ด์ ์ ์ด์ผ๊ธฐ....
- 2014๋
๊ฒฝ, ๋ฆฌ์กํธ ๋ฑ์ฅ๊ณผ ๋น์ทํ ์๊ธฐ์ Flux ํจํด, ๊ทธ๋ฆฌ๊ณ Flux ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ํ๋ฌ๋๋ฌ๋ค...
- Flux, alt, RefluxJS, NuclearJS, Fuxible, Fluxxor
- ๊ธฐ์กด MVC ํจํด์ ๋ชจ๋ธ ๋ทฐ๊ฐ ๊ฒ๋ ๋ง์์ ธ์ ๋ณต์ก๋๊ฐ ์ฆ๊ฐํ๋ ์ํฉ
- ์ํ ๋ณํ ์์ธ๊ณผ ์์น ์ถ์ ์ด ์ด๋ ค์
- (ํ์ด์ค๋ถ) ์๋ฐฉํฅ์ด ๋ฌธ์ ๋ค. -> ๋จ๋ฐฉํฅ์ผ๋ก ๋ฐ์ดํฐ ํ๋ฆ ๋ณ๊ฒฝ
- Action -> Dispatcher -> Model -> View
- ์์ ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ ์ ๋ ธ๋ ฅ
| ๊ตฌ๋ถ | ์ญํ | ์๋ | | ---------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------ | | action | ์์ ์ ์ฒ๋ฆฌํ ์ก์ , ์ก์ ๋ฐ์ ์ ํฌํจ์ํฌ ๋ฐ์ดํฐ | ์ก์ ํ์ ๊ณผ ๋ฐ์ดํฐ๋ฅผ ์ ์ํด ๋์คํจ์ณ๋ก ๋ณด๋ | | dispatcher | ์ก์ ์ ์คํ ์ด์ ๋ณด๋ | ์ฝ๋ฐฑ ํจ์ ํํ๋ก, ์์ ์ก์ ์ด ์ ์ํ ํ์ ๊ณผ ๋ฐ์ดํฐ๋ฅผ ์คํ ์ด์ ๋ณด๋ | | store | ์ค์ ์ํ์ ๋ฐ๋ฅธ ๊ฐ๊ณผ ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ ๋ฉ์๋ | ์ก์ ํ์ ์ ๋ฐ๋ผ, ์ด๋ป๊ฒ ๋ณ๊ฒฝํ ์ง ์ ์๋์ด ์์ | | view | (๋ฆฌ์กํธ ์ปดํฌ๋ํธ์ ํด๋น) ์คํ ์ด์์ ๋ง๋ค์ด์ง ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ํ๋ฉด์ ๋๋๋ง | ์ก์ ์ ํธ์ถํด์ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ํ ์ ์์ |
Redux์ ๋๋ฅ๋ฑ์ฅ
- ๋น์ ์์ฅ์ ์ง๋ฐฐํจ
- Flux ๊ตฌ์กฐ + Elm ์ํคํ
์ฒ ๋์
: ์นํ์ด์ง๋ฅผ ์ ์ธ์ ์ผ๋ก ์์ฑํ๊ธฐ ์ํ ์ธ์ด
- model(์ํ), view(HTML), update(๋ชจ๋ธ ์์ ๋ฐฉ์)
- ๋จ์
- ์ํ ๊ด๋ฆฌ๋ฅผ ์ํ ์ก์ ํ์ ์ ์ธ, creator ํจ์ ์์ฑ, dispatcher์ selector
- ๋ณด์ผ๋ฌํ๋ ์ดํธ๊ฐ ์งฑ ๋ง์ (์ง๊ธ์ ๋ง์ด ๊ฐ์ํ๋จ)
Context API์ useContext
- ๋ฆฌ์กํธ 16.3 ์ด์ => getChildContext()๋ฅผ ์ฌ์ฉํด context๋ฅผ ๋ค๋ฃธ
- ์์ ์ปดํฌ๋ํธ ๋๋๋ง ์, getChildContext ํธ์ถ -> ๋ฆฌ๋๋๋ง
- context๋ฅผ ์ธ์๋ก ๋ฐ์์ผํด์, ์ปดํฌ๋ํธ์ ๊ฒฐํฉ๋๊ฐ ๋์์ง
- ๋ฆฌ์กํธ 16.3 => Context API
Hook, React Query, SWR(Vercel)
- ํ -> ์ด์ ์๋ ๋ณผ ์ ์์๋ ๋ฐฉ์์ ์ํ ๊ด๋ฆฌ ๋ฑ์ฅ
- React Query(Tanstack Query), SWR
- fetch ๊ด๋ฆฌ์ ํนํ, API ํธ์ถ์ ๋ํ ์ํ๋ฅผ ๊ด๋ฆฌ
- HTTP ์์ฒญ์ ํนํ๋ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
Recoil(ํ์ด์ค๋ถ), Zustand, Jotai, Valtio
- ๋ฒ์ฉ์ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- ์์ ํฌ๊ธฐ์ ์ํ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ์ถ์ธ
- peerDependencies => react 16.8^
Local State: (1)useState, (2)useReducer
โป๏ธ useReducer๋ก useState ๋ง๋ค๊ธฐ
- (ํ์
)
Initializer
ํ์ ์์ ๋ค๋ฆญ ํ์ T
์ ๋ํ์ฌT
๋๋T์ ์ด์ ์ํ
๋ฅผ ์ธ์๋ก ๋ฐ์T
ํ์ ์ ๋ฐํํ๋ ํจ์ ํ์- ์ด๋ ์ํ ์
๋ฐ์ดํธ ์
์ํ ๊ฐ
๋๋์ํ๋ฅผ ์ ๋ฐ์ดํธํ๋ ํจ์
๋ฅผ action์ผ๋ก ์ ๋ฌํ ์ ์์์ ์๋ฏธํฉ๋๋ค.
- ์ด๋ ์ํ ์
๋ฐ์ดํธ ์
- ์ค์ ๋ก useState์ useReducer๋ก ๋ง๋ฆ
type Initializer<T> = T extends any ? T | ((prev: T) => T) : never;
// `useStateWithUseReducer`๋ initialState `initState`๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๊ณ , ๋ด๋ถ์ ์ผ๋ก `useReducer` ํ
์ ์ฌ์ฉํฉ๋๋ค.
function useStateWithUseReducer<T>(initState: T) {
// `useReducer` ํ
์ ์ํ(`state`)์ ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ ํจ์(`dispatch`)๋ฅผ ๋ฐํํฉ๋๋ค.
// ์ฌ๊ธฐ์ ๋ฆฌ๋์ ํจ์๋ ์ด์ ์ํ(`prev`)์ ์ก์
(`action`)์ ๋ฐ์ ์ ์ํ๋ฅผ ๊ณ์ฐํฉ๋๋ค.
// ์ก์
์ด ํจ์์ธ ๊ฒฝ์ฐ, ์ด์ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ํ ์
๋ฐ์ดํธ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
// ๊ทธ๋ ์ง ์์ผ๋ฉด ์ก์
์์ฒด๋ฅผ ์ ์ํ๋ก ์ฌ์ฉํฉ๋๋ค.
const [state, dispatch] = useReducer(
(prev: T, action: Initializer<T>) =>
typeof action === "function" ? action(prev) : action,
initState
);
// ์ํ์ ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ `dispatch` ํจ์๋ฅผ ๋ฐฐ์ด๋ก ๋ฌถ์ด ๋ฐํํฉ๋๋ค.
// ์ด๋ `useState` ํ
์ ๋ฐํ ๊ฐ๊ณผ ์ ์ฌํ ํํ์
๋๋ค.
return [state, dispatch];
}
โป๏ธ useState๋ก useReducer ๋ง๋ค๊ธฐ
import { useState, useCallback } from "react";
/**
* `useState`์ `useCallback`์ ์ฌ์ฉํ์ฌ `useReducer` ํ
์ ๊ธฐ๋ฅ์ ๋ชจ๋ฐฉํ๋ ์ปค์คํ
ํ
์
๋๋ค.
*
* @param {Function} reducer - ์ด์ ์ํ์ ์ก์
์ ๊ธฐ๋ฐ์ผ๋ก ์๋ก์ด ์ํ๋ฅผ ๊ฒฐ์ ํ๋ ๋ฆฌ๋์ ํจ์
* @param {any} initialState - ์ด๊ธฐ ์ํ ๊ฐ
* @param {Function} [initializer] - (optional) ์ด๊ธฐ ์ํ๋ฅผ ์์ฑํ ์ ์๋ ์ ํ์ ์ด๊ธฐํ ํจ์
* ์ ๊ณต๋๋ฉด, ์ด ํจ์์ ๋ฐํ ๊ฐ์ผ๋ก ์ด๊ธฐ ์ํ ์ค์
* @returns {[any, Function]} ํ์ฌ ์ํ ๊ฐ๊ณผ ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ dispatch ํจ์๋ฅผ ๋ฐํํฉ๋๋ค.
*/
function useReducerWithUseState(reducer, initialState, initializer) {
// ์ํ๋ฅผ ์ด๊ธฐํํฉ๋๋ค. initializer๊ฐ ์ ๊ณต๋๋ฉด, initializer๋ฅผ ์ฌ์ฉํ์ฌ initialState๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
// ๊ทธ๋ ์ง ์์ผ๋ฉด, initialState๋ฅผ ์ง์ ์ฌ์ฉํฉ๋๋ค.
const [state, setState] = useState(
initializer ? () => initializer(initialState) : initialState
);
// ์ก์
์ ๋ฐ์ ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ dispatch ํจ์๋ฅผ ์์ฑํฉ๋๋ค.
// ์ด ํจ์๋ ํ
์ผ๋ก ์ ๋ฌ๋ reducer ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค.
// useCallback์ผ๋ก ๋ํํ์ฌ ํจ์์ ๋ถํ์ํ ์ฌ์์ฑ์ ๋ฐฉ์งํ๊ณ , ๋ ๋๋ง ๊ฐ์ ์์ ์ ์ผ๋ก ์ ์ง๋๋๋ก ํฉ๋๋ค.
const dispatch = useCallback(
(action) => setState((prev) => reducer(prev, action)),
// reducer ํจ์๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ dispatch ํจ์๋ฅผ ์
๋ฐ์ดํธํ๊ธฐ ์ํด useCallback์ ์์กด์ฑ ๋ฐฐ์ด์ ํฌํจ์ํต๋๋ค.
// ์์กด์ฑ์ด ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๋ณ๊ฒฝ๋ ์ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฌํ ํจํด์ ์ฌ์ฉํฉ๋๋ค.
[reducer]
);
// ์ปดํฌ๋ํธ๊ฐ ์ํ๋ฅผ ์ฝ๊ณ ์ธ ์ ์๋๋ก ํ์ฌ ์ํ์ dispatch ํจ์๋ฅผ ๋ฐํํฉ๋๋ค.
// state๋ ํ์ฌ์ ์ํ, dispatch ํจ์๋ ์ก์
์ ๊ธฐ๋ฐ์ผ๋ก ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ ๋ฐ ์ฌ์ฉ
return [state, dispatch];
}
ํจ์ ์ธ๋ถ์์ ์ํ ๋ณํ๊ฐ ์ผ์ด๋ฌ์ ๋๋ฅผ ์ฐธ์กฐํด ๋ฆฌ๋๋๋ง
- ์ปดํฌ๋ํธ ์ธ๋ถ ์ด๋๊ฐ์ ์ํ๋ฅผ ๋๊ณ , ์ฌ๋ฌ ์ปดํฌ๋ํธ๊ฐ ๊ฐ์ด ์ธ ์ ์์ด์ผ ํจ
- ์ํ์ ๋ณํ๋ฅผ ์์์ฑ ์ ์์ด์ผ ํ๊ณ , ์ํ ๋ณํ ์ ๋ฆฌ๋๋๋ง์ ์ผ์ผ์ผ ์ปดํฌ๋ํธ๋ฅผ ์ต์ ์ํ๊ฐ ๊ธฐ์ค์ผ๋ก ๋๋๋งํด์ผ ํจ. (๋ชจ๋ ์ปดํฌ๋ํธ์์ ๋์ผ ์๋)
- ์์๊ฐ ์๋ ๊ฐ์ฒด์ธ ๊ฒฝ์ฐ, ๊ฐ์งํ์ง ์๋ ๊ฐ์ด ๋ณํ๋ฉด ๋ฆฌ๋๋๋ง x
- obj.a๊ฐ ๋ฐ๋์์ ๋ obj.b๋ฅผ ์์กดํ๋ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋๋๋ง๋๋ฉด x
- store, callback, subscribe
๊ฐ๋ตํ๊ฒ ๋ณด๊ธฐ: Recoil, Jotai, Zustand
Recoil
- 2020๋
, ํ์ด์ค๋ถ, ์ต์ ์ํ ๊ฐ๋
Atom์ ์ฒ์ ๋ฆฌ์กํธ ์ํ๊ณ์์ ์์
- ์ ๋ฐ์ดํธ 1๋ ์ , ์คํ ๋จ๊ณ
- RecoilRoot: Context store, ์ํ ๊ฐ์ ์ ๊ทผํ๋ ๋ฉ์๋๋ค, ๊ฐ ๋ณ๊ฒฝ => ํ์ ์ปดํฌ๋ํธ์ ์๋ฆผ
- atom: ์ต์ ์ํ ๋จ์, key, default
Jotai
- atom(์ต์ ์ํ ๋จ์)์ผ๋ก ์ํ๋ฅผ ๋ง๋ค๊ฑฐ๋, ํ์ ์ํ๋ฅผ ๋ง๋ฆ
- ์ฌ์ o
const [count, setCount] = useAtom(countAtom);
// countAtom
// atom์๋ ๊ฐ์ด ์ ์ฅ๋์ด์์ง ์๋ค.
{
init: 0,
read: (get) => get(config),
write: (get, set, update) =>
set(config, typeof update === "function" ? update(get(config)) : update),
};
Zustand
- ๋ฆฌ๋์ค ๋๋น ์ ์ ์ฝ๋ ์์ฑ / ์ฌ์ => ํ์ธ ํ์
- ๋ฒ๋ค ์ต์ํ o
- ts ์ง์ o
- ๋ฏธ๋ค์จ์ด o
=> TODO: ์์ ๋ ์ดํด๋ณด๊ธฐ 5.2.2~5.2.4
โ๏ธ English
resilient /rษหzilฤษnt/
de facto ์
๊ณ ํ์ค, De facto is Latin for "of fact", de jure
Tearing