๐ ์ฌ์ฉ์ ์ ์ ํ ๊ณผ ๊ณ ์ฐจ ์ปดํฌ๋ํธ ์ค ๋ฌด์์ ์จ์ผ ํ ๊น?
1๏ธโฃ ์ฌ์ฉ์ ์ ์ ํ
์๋ก ๋ค๋ฅธ ์ปดํฌ๋ํธ ๋ด๋ถ์์ ๊ฐ์ ๋ก์ง์ ๊ณต์ ํ๊ณ ์ ํ ๋ ์ฃผ๋ก ์ฌ์ฉ๋๋ ๊ฒ์ด ๋ฐ๋ก ์ฌ์ฉ์ ์ ์ ํ ์ด๋ค.
์ฌ์ฉ์ ์ ์ ํ ์ ๋ฐ๋์ use๋ก ์์ํ๋ ํจ์๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค. react-hooks/rules-of-hook์ ๋์์ ๋ฐ๊ธฐ ์ํด์.
๋ค์์ fetch๋ฅผ ์ํํ๋ ์ฌ์ฉ์ ์ ์ ํ ์ด๋ค.
import { uesEffect, useState } from "react"; function useFetch<T>(url: string, { method, body }: { method: string; body?: XMLHttpRequestBodyInit }) { const [result, setResult] = useState<T | undefined>(); const [isLoading, setIsLoading] = useState<boolean>(false); const [ok, setOk] = useState<boolean | undefined>(); const [status, setStatus] = useState<number | undefined>(); useEffect(() => { const abortController = new AbortController(); (async () => { //IIFE setIsLoading(true); const res = await fetch(url, { method, body, signal: abortController }); setOk(response.ok); setStatus(response.status); if (response.ok) { const apiResult = await res.json(); setResult(apiResult); } setIsLoading(false); })(); // IIFE ์คํ return () => { abortController.abort(); }; }, [url, method, body]); return { ok, result, isLoading, status }; }
2๏ธโฃ ๊ณ ์ฐจ ์ปดํฌ๋ํธ
- HOC, Higher Order Component. ์ปดํฌ๋ํธ ์์ฒด์ ๋ก์ง์ ์ฌ์ฌ์ฉํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ด๋ค.
- ์๋ฐ์คํฌ๋ฆฝํธ์ ์ผ๊ธ ๊ฐ์ฒด, ํจ์์ ํน์ง์ ์ด์ฉํ๋ฏ๋ก ๋ฆฌ์กํธ๊ฐ ์๋๋๋ผ๋ jsํ๊ฒฝ์์ ์ฌ์ฉํ ์ ์๋ค.
- ๋ฆฌ์กํธ์์์ ์ ๋ช ํ ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ก React.memo๊ฐ ์๋ค.
โReact.memo?
๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ ์๋ก ๋ ๋๋ง ๋ ๋๋ง๋ค ์์ ์ปดํฌ๋ํธ๋ ์๋ก ๋ ๋๋ง๋๋ค.
์์ ์ปดํฌ๋ํธ์ props๊ฐ ๋ณ๊ฒฝ๋์ง ์์์์๋, ๋ ๋๋ง์ด ์ผ์ด๋๋๋ฐ, ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ง๋ค์ด์ง ๋ฆฌ์กํธ์ ๊ณ ์ฐจ ์ปดํฌ๋ํธ๊ฐ React.memo์ด๋ค.
๊ทธ๋ ๋ค๋ฉด, ์ปดํฌ๋ํธ๋ ๊ฐ์ด๋ผ๋ ๊ด์ ์์ ๋ณธ๋ค๋ฉด React.memo๋์ useMemo๋ฅผ ์ฌ์ฉํด๋ ๋์ง ์์๊น?
function MemoizedChild = () => { return useMemo(() => <ChildComponent value="hello"/>) }) function ParentComponent() { const [state, setState] = useState(1); const handleChange = (e: ChangeEv๋t<HTMLInputElement>) => { setState(Number(e.target.value)) } return ( <> <input type="number" value={state} onChange={handleChange} /> <MemoizedChild/> </> ) }
โ ๊ณ ์ฐจํจ์๋ ๋ฌด์์ธ๊ฐ?
- ๊ณ ์ฐจํจ์์ ์ ์๋ ํจ์๋ฅผ ์ธ์๋ก ๋ฐ๊ฑฐ๋ ๊ฒฐ๊ณผ๋ก ๋ฐํํ๋ ํจ์์ด๋ค.
- ์์๋ก, useState์ ๊ฒฝ์ฐ, ํด๋ก์ ๋ฅผ ์ฌ์ฉํ๋ค. ์ฆ์์คํํจ์๋ฅผ ๋ฐํํ๋ ๊ณ ์ฐจํจ์์ด๋ค.
- ๊ณ ์ฐจํจ์๋ฅผ ํ์ฉํ๋ฉด ํจ์๋ฅผ ์ธ์๋ก ๋ฐ๊ฑฐ๋ ์๋ก์ด ํจ์๋ฅผ ๋ฐํํด ์์ ํ ์๋ก์ด ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด ๋ผ ์ ์๋ค.
โ๏ธ๊ณ ์ฐจํจ์๋ฅผ ํ์ฉํ์ฌ ๋ฆฌ์กํธ ๊ณ ์ฐจ ์ปดํฌ๋ํธ ๋ง๋ค๊ธฐ
function withLoginComponent<T>(Component: ComponentType<T>) {
return function (props: T & LoginProps) {
const { loginRequired, ...restProps } = props;
if (loginRequired) {
return <>๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค</>;
}
return <Component {...(restProps as T)} />;
};
}
- ๋ฌผ๋ก ์ด๋ฐ ์ธ์ฆ ์ฒ๋ฆฌ๋ ์๋ฒ๋จ์์ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ํจ์ฌ ํจ์จ์ ์ผ ๊ฒ์ด๋ค.
- ๋ฆฌ์กํธ์ ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ ๋ง์ฐฌ๊ฐ์ง๋ก with๋ก ์์ํ๋ ์ด๋ฆ์ ์ฌ์ฉํด์ผํ๋ค.
- ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ ๋ถ์ ํจ๊ณผ๋ฅผ ์ต์ํํด์ผ ํ๋ค. ์ฆ props๋ฅผ ์์๋ก ์์ , ์ถ๊ฐ, ์ญ์ ํ๋ ์ผ์ ์์ด์ผ ํ๋ค.
const Component = withHigherOrderComponent(
withHigherOrderComponent1(
withHigherOrderComponent2(
withHigherOrderComponent3(
withHigherOrderComponent4(
withHigherOrderComponent5(
return <div>Hello</div>
)))))
- ์ฌ๋ฌ๊ฐ์ ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ฅผ ๋ฐ๋ณต์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, ๋ณต์ก์ฑ์ด ์ปค์ง๋ฏ๋ก ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ ์ต์ํ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
3๏ธโฃ ์ฌ์ฉ์ ์ ์ ํ ๊ณผ ๊ณ ์ฐจ ์ปดํฌ๋ํธ ์ค ๋ฌด์์ ์จ์ผ ํ ๊น?
โ๏ธ ์ฌ์ฉ์ ์ ์ ํ ์ด ํ์ํ ๊ฒฝ์ฐ
- ๋จ์ํ useState, useEffect์ ๊ฐ์ด ๋ฆฌ์กํธ์์ ์ ๊ณตํ๋ ํ ์ผ๋ก ๊ณตํต ๋ก์ง์ ๊ฒฉ๋ฆฌํ ์ ์๋ค๋ฉด, ์ฌ์ฉ์ ์ ์ ํ ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
โ๏ธ ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ๊ฒฝ์ฐ
- ์ ํ๋ฆฌ์ผ์ด์ ๊ด์ ์์ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ถ๊ณ ๋ก๊ทธ์ธ์ ์๊ตฌํ๋ ๊ณตํต ์ปดํฌ๋ํธ๋ฅผ ๋ ธ์ถํ๋ ๊ฒ์ด ์ข์ ๊ฒฝ์ฐ.
function Hook() {
const { loggedIn } = useLogin();
if (!loggedIn) {
return <LoginComponent />;
}
return <div>Hi</div>;
}
const HOC = withLoginComponent(() => {
return <div>Hi</div>;
});
- ์ฌ์ฉ์ ์ ์ ํ ์ ํด๋น ์ปดํฌ๋ํธ๊ฐ ๋ฐํํ๋ ๋ ๋๋ง ๊ฒฐ๊ณผ๋ฌผ์ ์ํฅ์ ๋ฏธ์น๊ธฐ ์ด๋ ต๊ธฐ ๋๋ฌธ์, ์ด๋ฌํ ๊ฒฝ์ฐ ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ฉด ์ข๋ค.