ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프로그래머스 데브코스 - 8월 4주차 WIL
    React 2023. 8. 27. 23:36

     

    🔔 서론

    어느덧 데브코스의 리액트 과정이 2/3가 지나가는 시점이다. 생각보다 내가 몰랐던 내용들에 많이 노출되고 있다는 즐거움 반, '내가 이렇게나 모르는게 많았는데 리액트를 했다고 생각한거야?' 라는 허탈함 반으로 열심히 학습중이다. 이번 주 WIL은 React hook과 자주 사용되는 로직을 별도로 관리하는 custom hook에 대한 내용을 다룰 것이다.


    🎁 React Hook

    Hook은 함수 컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 "연동(hook into)" 할 수 있게 해주는 함수다. - React 공식 문서

    Hook은 React 16.8v부터 추가된 기능으로 class 형식의 컴포넌트에서만 가능했던 state 관리 및 라이프 사이클 등을 함수형 컴포넌트에서도 사용할 수 있게 만들어주는 새로운 기능이다.

    • Hook은 class 안에서 동작하지 않는다. 대신 class 없이도 react를 사용할 수 있게 한다.
    • React는 useState, useEffect등 내장 Hook을 몇가지 제공한다.
    • 컴포넌트 간에 상태 관련 로직을 사용하기 위해 Hook을 직접 만드는 것도 가능하다.

     

    📌 React가 Hook을 도입한 목적

    React Hook은 주로 class component로 사용되어온 React의 불편함과 문제점을 해결하기 위해 개발되었는데, React Hook이 나오기 전에는 생명주기를 함수형 컴포넌트에서는 사용하지 못 했기 때문에 함수형 컴포넌트가 더 간결하고 빠르더라도 클래스형 컴포넌트를 써왔다.

    컴포넌트에서 상태관련 로직을 사용할 때 Hook이 도입되기 이전에는 고차 컴포넌트 (HOC: High Order Component)나 render props같은 패턴을 통해 문제를 해결했지만, 이런 패턴들은 코드의 추적을 어렵게 했고, 이런 패턴들을 사용하다보면 많은 레이어들로 둘러쌓인 wrapper hell을 겪게되어 코드가 복잡해지는 문제점이 있었다.

    이러한 문제점을 해결하고자 React는 상태 관련 로직을 추상화해 독립적인 테스트와 재사용이 가능하여 레이어 변화 없이 재사용할 수 있는 Hook을 도입했다.

    또한 기존의 라이프사이클 메서드 기반이 아닌 로직 기반으로 컴포넌트를 나눌 수 있어 함수 단위로 쪼갤 수 있게 되었다.

     

    📌 Hook 종류

    기본 hook

    1. useState
    2. useEffect
    3. useContext

     

    추가 hook

    1. useReducer
    2. useCallback
    3. useMemo
    4. useRef
    5. useImperativeHandle
    6. useLayoutEffect
    7. useDebugValue

    🎁 Custom Hook

    종종 상태 관련 로직을 컴포넌트 간에 재사용하고 싶은 경우가 생긴다. 이 문제를 해결하기 위한 전통적인 방법이 두 가지 있었는데, higher-order components와 render props가 그것이다. Custom Hook은 이들 둘과는 달리 컴포넌트 트리에 새 컴포넌트를 추가하지 않고도 이것을 가능하게 해준다. - React 공식 문서

    위에서 React가 Hook을 도입한 목적중의 하나였던 상태 관련 로직 재사용에 대한 해결책이 이 Custom Hook 이다.

    간단한 토글버튼 예시 하나를 만들어보자

    import { useCallback, useState } from 'react'
    
    const useToggle = (initialState = false) => {
      const [state, setState] = useState(initialState)
      const toggle = useCallback(() => setState(state => !state), [])
      
      return [state, toggle]
    }
    
    export default useToggle

    이벤트가 일어나면 state를 toggle하는 로직을 useToggle이라는 custom hook으로 만들고
    반환 값으로 state와 toggle함수를 리턴한다.

     

    import styled from '@emotion/styled';
    import useToggle from '../../hooks/useToggle';
    
    /** 
    * styled component 생략
    */
    
    const Toggle = ({
      name,
      on = false,
      disabled,
      onChange,
      ...props
    }) => {
      const [checked, toggle] = useToggle(on)
    
      const handleChange = (e) => {
        toggle()
        onChange && onChange()
      }
    
      return (
        <ToggleContainer {...props}>
          <ToggleInput 
            type='checkbox' 
            name={name}
            checked={checked}
            disabled={disabled}
            onChange={handleChange}
          />
          <ToggleSwitch />
        </ToggleContainer>
      )
    }
    
    export default Toggle

    이 후 구현부에서 체크박스에 변화가 있을 때마다 useToggle hook에서 반환된 toggle 함수를 실행시켜 새로운 state를 받는다

     

     

    이렇게 상태관련 로직과 구현하는 컴포넌트를 분리하면 간편하게 사용할 수있다. 내부 동작을 숨기고 사용하는 측에서 내부 동작을 믿고 사용할 수 있게되고, 즉 '어떻게 구현할 것인가?' 보다 '무엇을 구현할 것인가?'에 집중할 수 있게 된다.


    💊 후기? 느낀점?

    일전에 vanilla javascript를 학습할 때 클래스 기반 컴포넌트와 함수형 컴포넌트의 차이점과 왜 요즘은 함수형 컴포넌트를 선호할까? 에대한 질문을 스스로에게 던져본적이 있다. 아쉽게도 그 당시에는 질문 수준에 그치고 한 단계 나아가는 과정을 겪지 않았는데 마침 이번 포스팅 주제인 Hook을 공부하던 와중 그 이유에 대해 조금은 알게 된 것 같았다.

    'React' 카테고리의 다른 글

    프로그래머스 데브코스 - 8월 3주차 WIL  (0) 2023.08.21
Designed by Tistory.