React์˜ Hook

ํ•™์Šต ํ‚ค์›Œ๋“œ

  • React Hook ์ด๋ž€

    • HOC ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ

React Hook

  • Hook์€ ๋ฆฌ์•กํŠธ v16.8์— ์ƒˆ๋กœ ๋„์ž…๋œ ๊ธฐ๋Šฅ์ด๋‹ค.

  • ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ ๊ณ ์œ  ๊ธฐ๋Šฅ์ธ ์ƒํƒœ(state)๊ด€๋ฆฌ์™€ ๋ผ์ดํ”„์‚ฌ์ดํด ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์„ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ ์“ธ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜๋“ค์„ ์ด์นญํ•œ๋‹ค.

๐ŸŒŽ React Hook์˜ ๋“ฑ์žฅ ๋ฐฐ๊ฒฝ

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ(Class Component)์™€ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ(Functional Component)๋กœ ๋‚˜๋‰œ๋‹ค. ๊ธฐ์กด์˜ ๊ฐœ๋ฐœ๋ฐฉ์‹์€ ์ผ๋ฐ˜์ ์œผ๋กœ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋˜ state์ด๋‚˜ Life Cycle Method๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ์—๋งŒ ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด์—ˆ๋‹ค.

์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•˜๋‹ˆ ๋ช‡๊ฐ€์ง€ ๋ฌธ์ œ์ ๋“ค์ด ์žˆ์—ˆ๋‹ค.

๐Ÿšจ Wrapper Hell (์ƒํƒœ๋กœ์ง์˜ ์žฌ์‚ฌ์šฉ์„ฑ ์–ด๋ ค์›€)

๋ฆฌ์•กํŠธ๋ฅผ ์“ฐ๋‹ค ๋ณด๋ฉด ์ž์ฃผ ์“ฐ๋Š” ๋กœ์ง์„ ๋”ฐ๋กœ ๋นผ๋‚ด์„œ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์žˆ๋Š”๋ฐ HOC(High Order Component)๋ฅผ ์ด์šฉํ•ด์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ๋‹ค.

๐Ÿ“– HOC(High Order Component) ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ ํ™”๋ฉด์—์„œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋กœ์ง๋งŒ์„ ๋ถ„๋ฆฌํ•ด์„œ component๋กœ ๋งŒ๋“ค๊ณ , ์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅํ•œ UI์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ๋ถ€๋ถ„์€ Parameter๋กœ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•˜๋Š” ํŒจํ„ด โ‡’ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„์„œ ์ƒˆ๋กœ์šด ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜

ํ•˜์ง€๋งŒ HOC์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ, Wrapper hell์ด๋ผ๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ ํ–ˆ๋‹ค. "Wrapper hell" ์€ ์ค‘์ฒฉ๋˜๋Š” Component๊ฐ€ ๋งŽ์•„์ ธ depth๊ฐ€ ๊นŠ์–ด์ง€๊ฒŒ ๋˜์–ด ์ฝ”๋“œ ์ถ”์ ์„ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค๊ณ  ์ปดํฌ๋„ŒํŠธ์˜ ์žฌ๊ตฌ์„ฑ์„ ๊ฐ•์š”ํ•˜๊ฒŒ ํ–ˆ๋‹ค.

HOC ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ

SomeComponent๊ฐ€ ๋งˆ์šฐ์Šค ํฌ์ง€์…˜, window ํฌ๊ธฐ, ์œ ์ € ์œ„์น˜ ๋“ฑ์˜ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด HOC๊ตฌ์กฐ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ด๋Ÿฐ ๊ตฌ์กฐ๋Š” ๊ฐ€๋…์„ฑ๋„ ์ข‹์ง€์•Š๊ณ  element๋ฅผ ์ฐพ๊ธฐ ํž˜๋“ค์–ด์ง„๋‹ค.

const HocHell = () => {
  return (
    <Hoc1>
      <WithMousePosition>
        <WithWindowSize>
          <WithUserLocation>
            <SomeComponent />
          </WithUserLocation>
        </WithWindowSize>
      </WithMousePosition>
    </Hoc1>
  );
};

Custom Hook์„ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ

Custom Hook์„ ํ†ตํ•ด ๋ชจ๋“ˆํ™”ํ•˜์—ฌ SomeComponent ์ „๋‹ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ณ„์ธต๊ตฌ์กฐ๊ฐ€ ๋‹จ์ˆœํ•ด์ง€๋ฉฐ ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

const WithHook = () => {
  const mousePosition = useMousePosition()
  const windowSizes = useWindowSize()
  const userLocation = useUserLocation()
  
  return (
    <SomeComponent
      mousePosition={mousePosition}
      windowSizes={windowSizes}
      userLocation={useLocation}
    />
  )
}

โœ… Hook์€ ๊ณ„์ธต์˜ ๋ณ€ํ™” ์—†์ด ์ƒํƒœ ๊ด€๋ จ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

๐Ÿšจ Huge Components (์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šด ๋ณต์žกํ•œ ์ปดํฌ๋„ŒํŠธ)

๐Ÿค” ๋งŒ์•ฝ ํ™ˆ ์ปดํฌ๋„ŒํŠธ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ ๋์„ ๋•Œ ๊ทธ๋ฆฌ๊ณ  PathName Prop์ด ๋ณ€๊ฒฝ๋์„ ๋•Œ lookups ๋ฐ์ดํ„ฐ๋ฅผ API์—์„œ ๋ฐ›์•„์™€์•ผ ํ•œ๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ?

Classํ˜• ์ปดํฌ๋„ŒํŠธ์˜ LifeCycle ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ

componentDidMount, componentDidUpdate์˜ LifeCycle API๋ฅผ ์ด์šฉํ•˜์—ฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌ ํ•˜๊ฒŒ ๋˜์–ด ํ•จ์ˆ˜๋Š” ๋‹จ์ผ ์ฑ…์ž„ ์›์น™์„ ๋ฒ—์–ด๋‚˜๊ฒŒ ๋˜๊ณ , ์ฝ”๋“œ๋Š” ๋ณต์žกํ•ด์ง€๋ฉฐ, ํ…Œ์ŠคํŠธ๋Š” ์ ์ฐจ ์–ด๋ ค์›Œ์ง„๋‹ค.

class Home extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      lookups: null
    };
    // this๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ”์ธ๋“œ
    this.fetchLookups = this.fetchLookups.bind(this);
  }

  componentDidMount() {
    this.fetchLookups(this.props.pathName);
  }

  componentDidUpdate(prevProps) {
    // pathName prop์ด ๋ณ€๊ฒฝ ๋˜์—ˆ์„ ๋•Œ
    if (prevProps.pathName !== this.props.pathName) {
      this.fetchLookups(this.props.pathName);
    }
  }

  fetchLookups(pathName) {
    fetchApi({ url: `/lookup?url=${pathName}` }).then((lookups) => {
     // lookups ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜ ๋˜๋ฉด state์—…๋ฐ์ดํŠธ
      this.setState({
        lookups
      });
    });
  }

  render() {
    if (!this.state.lookups) return null;
    return <pre>{JSON.stringify(this.state.lookups)}</pre>;
  }

}

ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์˜ LifeCycle ๊ด€๋ฆฌํ•˜๋Š” Hook์„ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ

useState, useEffect์˜ Hook์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๋Š” ๊ฐ„๊ฒฐํ•ด์ง€๊ณ  ๋ฐ˜๋ณต์ ์ด๊ณ  ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ๋“ค์ด ์ œ๊ฑฐ๋œ๋‹ค.

const HomeWithHook = ({ pathName }) => {
  const [lookups, updateLookups] = useState(null);
  useEffect(() => {
    if (pathName) {
      fetchApi({ url: `/lookup?url=${pathName}` }).then((lookups) => {
        updateLookups(lookups);
      });
    }
  // dependency๋ฅผ pathName์œผ๋กœ ํ•ด์ฃผ๋ฉด ๋งจ ์ฒ˜์Œ์— ํ•œ๋ฒˆ pathName์ด ๋ณ€๊ฒฝ ๋˜์—ˆ์„ ๋•Œ ๋˜ ์‹คํ–‰
  }, [pathName]);
  if (!lookups) return null;
  return <pre>{JSON.stringify(lookups)}</pre>;
};

โœ… Hook์„ ํ†ตํ•ด ์„œ๋กœ ๋น„์Šทํ•œ ๊ฒƒ์„ ํ•˜๋Š” ์ž‘์€ ํ•จ์ˆ˜์˜ ๋ฌถ์Œ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‚˜๋ˆ„๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿšจ Confusing Classes (์‚ฌ๋žŒ๊ณผ ๊ธฐ๊ณ„๋ฅผ ํ˜ผ๋™์‹œํ‚ค๋Š” Class)

React์—์„œ์˜ ClassComponent๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” JavaScript์˜ this ํ‚ค์›Œ๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์•Œ์•„์•ผ ํ•œ๋‹ค. JavaScript์˜ this ํ‚ค์›Œ๋“œ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๋‹ค๋ฅธ ์–ธ์–ด์—์„œ์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™ํ•จ์œผ๋กœ ํ˜ผ๋ž€์„ ์œ ๋ฐœํ•˜๊ณ  ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ๊ตฌ์„ฑ์„ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ ๋‹ค.

โœ… Hook์€ Class์—†์ด React๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ์‹œํ•œ๋‹ค.

โœ๐Ÿป React Hook ์ •๋ฆฌ

  • React hook 16.8 ๋ฒ„์ „ ์ดํ›„ ๋„์ž…๋œ ๊ธฐ๋Šฅ์ด๋‹ค.

  • ๊ธฐ์กด์— React๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋˜ ๋ฌธ์ œ์ ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด hook์ด ํƒ„์ƒํ•˜์˜€๋‹ค.โ‡’ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์˜ Update

    • Class ์ปดํฌ๋„ŒํŠธ์˜ ๋ฌธ์ œ โ‡’ this ํ‚ค์›Œ๋“œ, extends ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•œ ์ƒ์†์œผ๋กœ ๋ฐ˜๋ณต์ ์ธ ์ฝ”๋“œ ์ž‘์„ฑ

    • ์ƒํƒœ ๊ด€๋ฆฌ ๋กœ์ง(์ปดํฌ๋„ŒํŠธ)์˜ ์žฌ์‚ฌ์šฉ ์–ด๋ ค์›€ โ‡’ Custom hook ์ปดํฌ๋„ŒํŠธ์˜ ๋ชจ๋“ˆํ™”

    • Class ์ปดํฌ๋„ŒํŠธ์˜ LifeCycle(์ƒ๋ช…์ฃผ๊ธฐ)์™€ ๊ด€๋ จ๋œ ๋ฉ”์„œ๋“œ๋กœ ์ธํ•œ ๋ณต์žกํ•œ ์ปดํฌ๋„ŒํŠธ

  • Hook์„ ํ†ตํ•ด ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•˜๊ณ  ๊ฐ€๋…์„ฑ ์žˆ๊ฒŒ ํ•˜๋ฉฐ, ์žฌ์‚ฌ์šฉ์˜ ํšจ์œจ์„ ๊ทน๋Œ€ํ™” ์‹œํ‚ค๊ธฐ ์œ„ํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณต

๐Ÿ”— ์ฐธ๊ณ 

Last updated