๐Ÿ“š Books/๐Ÿ“• Advanced React

[Ch7] Higher-order components in modern world

nalong 2025. 2. 23. 14:57

React์˜ ๋‹ค์–‘ํ•œ ์กฐํ•ฉ ๊ธฐ์ˆ  ์ค‘ ํ•˜๋‚˜์ธ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ(Higher-Order Component, HOC)์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋ž€?

React ๊ณต์‹ ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด, HOC๋Š” ์ปดํฌ๋„ŒํŠธ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค. ์‰ฝ๊ฒŒ ๋งํ•ด, ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ ๋‚ด๋ถ€์—์„œ ํŠน์ • ๋กœ์ง์„ ์‹คํ–‰ํ•œ ํ›„ ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.

๊ธฐ๋ณธ์ ์ธ HOC ํŒจํ„ด

const withSomeLogic = (Component) => {
  return (props) => <Component {...props} />;
};
const Button = ({ onClick }) => (
  <button onClick={onClick}>Button</button>
);
const ButtonWithSomeLogic = withSomeLogic(Button);

HOC๋Š” ๊ธฐ์กด ์ปดํฌ๋„ŒํŠธ์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ตฌํ˜„ ๋ฐฉ์‹์ด ๊ฐ„๋‹จํ•˜๋ฉด์„œ๋„ ๊ฐ•๋ ฅํ•œ ํ™•์žฅ์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค.

๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ™œ์šฉํ•œ props ์ฃผ์ž…

HOC๋Š” ์ปดํฌ๋„ŒํŠธ์— props๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ์šฉ๋„๋กœ ์ž์ฃผ ์‚ฌ์šฉ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜์˜ ์ฝ”๋“œ์—์„œ๋Š” ํ…Œ๋งˆ ์ •๋ณด๋ฅผ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์— ์ž๋™์œผ๋กœ ์ „๋‹ฌํ•œ๋‹ค.

const withTheme = (Component) => {
  const theme = isDark ? "dark" : "light";
  return (props) => <Component {...props} theme={theme} />;
};

const Button = ({ theme }) => (
  <button className={theme}>Button</button>
);
const ButtonWithTheme = withTheme(Button);

์ด ํŒจํ„ด์„ ํ™œ์šฉํ•˜๋ฉด, ๊ฐ ์ปดํฌ๋„ŒํŠธ์—์„œ theme์„ ์ง์ ‘ ๊ด€๋ฆฌํ•  ํ•„์š” ์—†์ด, HOC๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ์ž๋™์œผ๋กœ ํ…Œ๋งˆ ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ ๋ฐฐ๊ฒฝ

HOC๋Š” Redux์˜ connect ํ•จ์ˆ˜, React Router์˜ withRouter ๋“ฑ์—์„œ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜์—ˆ๋‹ค.

ํ•˜์ง€๋งŒ ํ›… ๋“ฑ์žฅ ์ดํ›„ HOC์˜ ์‚ฌ์šฉ ๋นˆ๋„๊ฐ€ ์ค„์–ด๋“ค์—ˆ์œผ๋ฉฐ, ๋งŽ์€ ๊ฒฝ์šฐ useTheme ๊ฐ™์€ ํ›…์„ ํ™œ์šฉํ•˜์—ฌ HOC๋ฅผ ๋Œ€์ฒดํ•˜๊ณ  ์žˆ๋‹ค.

const Button = () => {
  const { theme } = useTheme();
  return <button className={theme}>Button</button>;
};

HOC๋Š” ํ•œ๋•Œ ์ฝ”๋“œ์˜ ๋ชจ๋“ˆํ™”์™€ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๋Š” ์ค‘์š”ํ•œ ํŒจํ„ด์ด์—ˆ์ง€๋งŒ, ์ง€๊ธˆ์€ ํ›…์„ ์ด์šฉํ•œ ํ•ด๊ฒฐ ๋ฐฉ์‹์„ ์„ ํ˜ธํ•œ๋‹ค.

๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ ์‚ฌ๋ก€

โœ… HOC๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์‹คํ–‰ ์‹œ ๊ณตํ†ต์ ์ธ ๋กœ์ง(์˜ˆ: ๋กœ๊น…)์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

export const withLoggingOnClick = (Component) => {
  return (props) => {
    const onClick = () => {
      console.log("Log on click something");
      if (props.onClick) props.onClick();
    };
    return <Component {...props} onClick={onClick} />;
  };
};
export const ButtonWithLoggingOnClick = withLoggingOnClick(Button);

 

โœ… ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” HOC๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

export const withLoggingOnMount = (Component) => {
  return (props) => {
    useEffect(() => {
      console.log("log on mount");
    }, []);
    return <Component {...props} />;
  };
};

HOC๋ฅผ ํ™œ์šฉํ•˜๋ฉด, ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ๋ช…์ฃผ๊ธฐ ๋กœ์ง์„ ์ค‘๋ณต ์ž‘์„ฑํ•  ํ•„์š” ์—†์ด, ํ•œ ๊ณณ์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

โœ… ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํŠน์ • DOM ์ด๋ฒคํŠธ๋ฅผ ๊ฐ€๋กœ์ฑŒ ์ˆ˜๋„ ์žˆ๋‹ค.

export const withSuppressKeyPress = (Component) => {
  return (props) => {
    const onKeyPress = (event) => event.stopPropagation();
    return (
      <div onKeyPress={onKeyPress}>
        <Component {...props} />
      </div>
    );
  };
};
const ModalWithSuppressedKeyPress = withSuppressKeyPress(Modal);

๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ์˜ ์žฅ๋‹จ์ 

โœ… ์žฅ์ 

  • ๋กœ์ง์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.
  • props๋ฅผ ์กฐ์ž‘ํ•˜์—ฌ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์œ ์—ฐํ•˜๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ƒ๋ช…์ฃผ๊ธฐ ์ด๋ฒคํŠธ๋‚˜ ํŠน์ • ๋™์ž‘์„ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

โŒ ๋‹จ์ 

  • ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ๊ฐ€ ๊นŠ์–ด์งˆ์ˆ˜๋ก ๋””๋ฒ„๊น…์ด ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๋‹ค.
  • ๋ถˆํ•„์š”ํ•œ ์ค‘์ฒฉ์ด ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค.
  • React์˜ ์ตœ์‹  ํŒจํ„ด(ํ›…)๊ณผ ๋น„๊ตํ–ˆ์„ ๋•Œ, ์ƒ๋Œ€์ ์œผ๋กœ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

์ •๋ฆฌ

  • ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹จ์ˆœํ•œ ํ•จ์ˆ˜๋กœ, ๊ธฐ์กด ์ปดํฌ๋„ŒํŠธ์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
  • props ์ฃผ์ž…, ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ํ–ฅ์ƒ, ์ƒ๋ช…์ฃผ๊ธฐ ์ด๋ฒคํŠธ ๊ด€๋ฆฌ, DOM ์ด๋ฒคํŠธ ๊ฐ€๋กœ์ฑ„๊ธฐ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ›… ๋“ฑ์žฅ ์ดํ›„ ์‚ฌ์šฉ ๋นˆ๋„๊ฐ€ ์ค„์—ˆ์ง€๋งŒ, ํŠน์ • ์ƒํ™ฉ์—์„œ๋Š” ์œ ์šฉํ•˜๊ฒŒ ํ™œ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ณ , ํŠน์ • ๊ธฐ๋Šฅ์„ ๋ถ„๋ฆฌํ•  ๋•Œ ํšจ๊ณผ์ ์ด์ง€๋งŒ, ํ•„์š” ์ด์ƒ์œผ๋กœ ์ค‘์ฒฉ๋˜๋ฉด ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ๋‹ค.