[๋ฆฌ์•กํŠธ ๋”ฅ ๋‹ค์ด๋ธŒ] 03-2 ์‚ฌ์šฉ์ž ์ •์˜ ํ›…๊ณผ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ ์ค‘ ๋ฌด์—‡์„ ์จ์•ผ ํ• ๊นŒ?

๐Ÿš€ ์‚ฌ์šฉ์ž ์ •์˜ ํ›…๊ณผ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ ์ค‘ ๋ฌด์—‡์„ ์จ์•ผ ํ• ๊นŒ?

1๏ธโƒฃ ์‚ฌ์šฉ์ž ์ •์˜ ํ›…

  1. ์„œ๋กœ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ๊ฐ™์€ ๋กœ์ง์„ ๊ณต์œ ํ•˜๊ณ ์ž ํ•  ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ ์‚ฌ์šฉ์ž ์ •์˜ ํ›…์ด๋‹ค.

  2. ์‚ฌ์šฉ์ž ์ •์˜ ํ›…์€ ๋ฐ˜๋“œ์‹œ use๋กœ ์‹œ์ž‘ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. react-hooks/rules-of-hook์˜ ๋„์›€์„ ๋ฐ›๊ธฐ ์œ„ํ•ด์„œ.

  3. ๋‹ค์Œ์€ 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๏ธโƒฃ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ

  1. HOC, Higher Order Component. ์ปดํฌ๋„ŒํŠธ ์ž์ฒด์˜ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.
  2. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ผ๊ธ‰ ๊ฐ์ฒด, ํ•จ์ˆ˜์˜ ํŠน์ง•์„ ์ด์šฉํ•˜๋ฏ€๋กœ ๋ฆฌ์•กํŠธ๊ฐ€ ์•„๋‹ˆ๋”๋ผ๋„ jsํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. ๋ฆฌ์•กํŠธ์—์„œ์˜ ์œ ๋ช…ํ•œ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋กœ React.memo๊ฐ€ ์žˆ๋‹ค.

โ“React.memo?

  1. ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ƒˆ๋กœ ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋Š” ์ƒˆ๋กœ ๋ Œ๋”๋ง๋œ๋‹ค.

  2. ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ props๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์Œ์—๋„, ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๋Š”๋ฐ, ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ๋ฆฌ์•กํŠธ์˜ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ React.memo์ด๋‹ค.

  3. ๊ทธ๋ ‡๋‹ค๋ฉด, ์ปดํฌ๋„ŒํŠธ๋„ ๊ฐ’์ด๋ผ๋Š” ๊ด€์ ์—์„œ ๋ณธ๋‹ค๋ฉด 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/>
            </>
        )
    }

โ“ ๊ณ ์ฐจํ•จ์ˆ˜๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

  1. ๊ณ ์ฐจํ•จ์ˆ˜์˜ ์ •์˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๋ฐ›๊ฑฐ๋‚˜ ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.
  2. ์˜ˆ์‹œ๋กœ, useState์˜ ๊ฒฝ์šฐ, ํด๋กœ์ €๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ฆ‰์‹œ์‹คํ–‰ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ณ ์ฐจํ•จ์ˆ˜์ด๋‹ค.
  3. ๊ณ ์ฐจํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•˜๋ฉด ํ•จ์ˆ˜๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๊ฑฐ๋‚˜ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ด ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

โ—๏ธ๊ณ ์ฐจํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฆฌ์•กํŠธ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

function withLoginComponent<T>(Component: ComponentType<T>) {
  return function (props: T & LoginProps) {
    const { loginRequired, ...restProps } = props;

    if (loginRequired) {
      return <>๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค</>;
    }

    return <Component {...(restProps as T)} />;
  };
}
  1. ๋ฌผ๋ก  ์ด๋Ÿฐ ์ธ์ฆ ์ฒ˜๋ฆฌ๋Š” ์„œ๋ฒ„๋‹จ์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ํšจ์œจ์ ์ผ ๊ฒƒ์ด๋‹ค.
  2. ๋ฆฌ์•กํŠธ์˜ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ with๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ด๋ฆ„์„ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.
  3. ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ถ€์ˆ˜ ํšจ๊ณผ๋ฅผ ์ตœ์†Œํ™”ํ•ด์•ผ ํ•œ๋‹ค. ์ฆ‰ props๋ฅผ ์ž„์˜๋กœ ์ˆ˜์ •, ์ถ”๊ฐ€, ์‚ญ์ œํ•˜๋Š” ์ผ์€ ์—†์–ด์•ผ ํ•œ๋‹ค.
const Component = withHigherOrderComponent(
    withHigherOrderComponent1(
        withHigherOrderComponent2(
            withHigherOrderComponent3(
                withHigherOrderComponent4(
                    withHigherOrderComponent5(
                        return <div>Hello</div>
    )))))
  1. ์—ฌ๋Ÿฌ๊ฐœ์˜ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ๋ณต์žก์„ฑ์ด ์ปค์ง€๋ฏ€๋กœ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋Š” ์ตœ์†Œํ•œ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

3๏ธโƒฃ ์‚ฌ์šฉ์ž ์ •์˜ ํ›…๊ณผ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ ์ค‘ ๋ฌด์—‡์„ ์จ์•ผ ํ• ๊นŒ?

โ—๏ธ ์‚ฌ์šฉ์ž ์ •์˜ ํ›…์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ

  1. ๋‹จ์ˆœํžˆ useState, useEffect์™€ ๊ฐ™์ด ๋ฆฌ์•กํŠธ์—์„œ ์ œ๊ณตํ•˜๋Š” ํ›…์œผ๋กœ ๊ณตํ†ต ๋กœ์ง์„ ๊ฒฉ๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์‚ฌ์šฉ์ž ์ •์˜ ํ›…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

โ—๏ธ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

  1. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ด€์ ์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์ถ”๊ณ  ๋กœ๊ทธ์ธ์„ ์š”๊ตฌํ•˜๋Š” ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒฝ์šฐ.
function Hook() {
  const { loggedIn } = useLogin();

  if (!loggedIn) {
    return <LoginComponent />;
  }

  return <div>Hi</div>;
}
const HOC = withLoginComponent(() => {
  return <div>Hi</div>;
});
  1. ์‚ฌ์šฉ์ž ์ •์˜ ํ›…์€ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฌผ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ธฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹๋‹ค.