3 분 소요

2022. 09. 01. , 09. 06. 수업내용 정리

Hook .. 개요, 장단점..


  • 소개

    • React 16.8 버전 (2019년도) 에 추가된 공식 라이브러리.
    • Class 형 컴포넌트에서만 쓸 수 있었던 state와 life cycle을 Function형 컴포넌트에서도 사용 가능.
    • 현재 공식문에서는, Class형 컴포넌트보다는 Function형 컴포넌트로 새로운 React 프로젝트를 만들기를 권장.
    • 단, 기존의 Class형 컴포넌트들을 Hook을 이용한 Function형 컴포넌트로 refactoring할 이유는 전혀 없음.



  • 사용이유

    • 클래스형 컴포넌트들은 method의 개념이므로, 리렌더링디 되더라도 render()를 제외한 나머지 method, state는 그대로 보존되어 있으나

      함수형 컴포넌트들은 리렌더링이 될 시, 함수 안에 작성된 모든 코드가 다시 실행됩니다.

    • 기존에 가지고 있던 상태(state)를 전혀 관리(기억)할 수 없게 만듭니다. 이는 리렌더링 시 무조건 새롭게 선언 & 초기화 & 메모리에 할당이 된다는 의미입니다. (메모리 자원을 사용하기에 함부로 남발하면 오히려 성능저하를 불러올 수 있음)
    • Hook에서 브라우저에 메모리를 할당 함으로서, 함수형 컴포년트가 상태(state)를 가질 수 있게 한 것입니다.
    • 그 밖에도 컴포넌트 사이에서 상태 로직 재사용의 어려움(render props, HOC 등)
    • 복잡한 (클래스형) 컴포넌트들은 이해하기 어려움 (각종 생명주기 함수들)
    • 클래스 자체 개념의 어려움(this)



  • 규칙

    • Hook에는 규칙이 있다. 이를 꼭 지켜야 정상적으로 hook이 실행되고 코드가 꼬이지 않습니다.


      1. 최상위에서만 Hook을 호출
        • React 함수(컴포넌트)의 최상위에서만 Hook을 호출 할 것.
        • 반복문, 조건문, 중첩된 함수등에서 호출 X
      2. React 함수에서만 Hook을 호출
        • Custom Hook에서는 호출 가능
        • 일반적인 Javascript 함수에서는 호출 X
      3. Hook을 만들 때 앞에 use 붙이기
        • 그래야만 한눈에 보아도 Hook 규칙이 적용되는지를 파악할 수 있기 때문 (공홈)
      4. React는 Hook 호출되는 순서에 의존
        • 한 컴포넌트에서 여러개의 hook이 사용되는 경우
        • hook은 위에서부터 아래로 순서에 맞게 동작한다.
      function Form() {
        // 1. name이라는 state 변수를 사용하세요.
        const [name, setName] = useState('Mary');
          
        // 2. Effect를 사용해 폼 데이터를 저장하세요.
        useEffect(function persistForm() {
          localStorage.setItem('formData', name);
        });
          
        // 3. surname이라는 state 변수를 사용하세요.
        const [surname, setSurname] = useState('Poppins');
          
        // 4. Effect를 사용해서 제목을 업데이트합니다.
        useEffect(function updateTitle() {
          document.title = name + ' ' + surname;
        });
          
        // ...
      }
      


      • Hook에 호출 순서에 따른 결과
      // ------------
      // 첫 번째 렌더링
      // ------------
      useState('Mary')           // 1. 'Mary'라는 name state 변수를 선언합니다.
      useEffect(persistForm)     // 2. 폼 데이터를 저장하기 위한 effect를 추가합니다.
      useState('Poppins')        // 3. 'Poppins'라는 surname state 변수를 선언합니다.
      useEffect(updateTitle)     // 4. 제목을 업데이트하기 위한 effect를 추가합니다.
          
      // -------------
      // 두 번째 렌더링
      // -------------
      useState('Mary')           // 1. name state 변수를 읽습니다.(인자는 무시됩니다)
      useEffect(persistForm)     // 2. 폼 데이터를 저장하기 위한 effect가 대체됩니다.
      useState('Poppins')        // 3. surname state 변수를 읽습니다.(인자는 무시됩니다)
      useEffect(updateTitle)     // 4. 제목을 업데이트하기 위한 effect가 대체됩니다.
          
      // ...
      


  • Hook의 최적화를 위해 신경써야할 요소

    1. 컴포넌트가 반드시 필요한 리랜더링만을 진행하는가?
    2. 랜더링이 발생한다면, property 및 method가 반드시 필요한 것만 재할당 할 수 있게 하는가?
    3. 위 2가지를 무시할만큼, 랜더링이 자주되는가? ) 따라서 메모리를 할당하면서 위의 2가지를 지키지 않아도 되는가?

  • 장점

    1. 함수형 컴포넌트로 코드 통일 가능

      -이전에는 state 유무로 클래스형과 함수형을 판별.

    2. useEffect로 클래스형 Lifecycle에 흩어져 있는 로직 묶음

      -클래스형 컴포넌트에서 로직을 재사용하기 위해 썼던 HOC나 render-props 같은 패턴이 가져오는 컴포넌트 트리의 불필요한 중첩을 없애줌.

      // class
      componentDidMount() {
          this.updateList(this.props.id);
      }	
           
      componentDidUpdate(prevProps) {
          if (prevProps.id !== this.props.id) {
              this.updateList(this.props.id);
          }
      }
           
      updateList = () => {
          feachList(id).then((list) => this.setState({list}));
      }
           
      // hooks
      useEffect(() => {
          feachList(id).then((res) => setRes(res));
      }, [id]);
      출처: https://developerntraveler.tistory.com/146 [개발여행의 블로그:티스토리]
      



  • 단점

    1. 호출되는 순서에 의존

      • hooks는 반복문, 조건문, 중첩된 함수 내에서 호출이 불가합니다.

      • 예를 들어 클릭하면 페이징되는 버튼을 구현하기 위해 useFetch를 사용하려고 한다면, react-async-hook 라이브러리를 사용하거나 custom hook을 만들어 해결해야 합니다.

      • hooks의 규칙을 따르기 위해 많은 리소스가 필요하고, 코드가 많아지면 복잡성이 증가합니다.

    2. useEffect의 빈틈

      • useEffect는 두번째 인수로 dependency list를 받고, 하나의 값이라도 변경됐을 때 useEffect 내부의 로직을 실행하여 라이프 사이클을 흉내냅니다.

      • React에서 hooks’ dependency array의 변경을 감지하기 위해 Object.js()메서드를 사용하는데, 대체로 원시 타입에 올바르게 작동합니다.

      • 참조형 데이터를 비교할 때는 렌더링 될 때 마다 참조 메모리 주소가 다르기 때문에 매번 실행됩니다.

      • useMemo를 사용하여 동일한 객체가 전달될 수 있도록 처리할 수 있지만, 개발자가 놓치고 넘어가기 쉬운 포인트인 것 같습니다.

    3. Hooks는 클로저에 의존적이다.

      • 프로그램이 커질수록 Hooks가 많아지는데, 클로저는 복잡성을 증가시킨다. 최신상태가 아닌 클로저는 해결하기 어렵습니다.
      function WatchCount() {
          const [count, setCount] = useState(0);
               
          useEffect(function() {
              setInterval(function log(){
                  console.log(`Count is: ${count}`);
              }, 2000);
          }, []);
               
        return (
            <div>
            	{count}
              <button onClick={()=>setCount(count+1)}>
                  Increase
              </button>
            </div>
        );
      }
      


      위 코드에서 출력된 count는 항상 0이다. console.log()는 생성될 때의 count(0)을 캡처하여 기억하고 있으므로, 계속 count는 0일 것입니다.
      해결하기 위해 하단과 변경할 수 있지만, 클로저 역시 예상하기 어렵습니다.

      function WatchCount() {
          const [count, setCount] = useState(0);
               
          useEffect(function() {
              setInterval(function log(){
                  console.log(`Count is: ${count}`);
              }, 2000);
              return function() {
                  clearInterval(id);
              };
              [count]
          );
               
        return (
            <div>
            	{count}
              <button onClick={()=>setCount(count+1)}>
                  Increase
              </button>
            </div>
        );
      }
      



  • Hook 종류

    자체적으로 제공하는 기본 Hook, 추가 Hook이 있고 사용자가 만들어서 사용할 수 있는 Custom Hook이 있습니다.

    • 기본 Hooks

      1. useState (동적 상태 관리)
      2. useEffect (side effect 수행 -mount/unmount/update)
      3. useContext (컴포넌트를 중첩하지 않고도 전역 값 쉽게 관리)


    • 추가 Hooks

      1. useReducer (복잡한 컴포넌트들의 state를 관리 -분리)
      2. useCallback (특정 함수 재사용)
      3. useMemo (연산한 값 재사용)
      4. useRef (DOM선택, 컴포넌트 안에서 조회/수정할 수 있는 변수 관리)
      5. useImperativeHandle
      6. useLayoutEffect
      7. useDebugValue

    ref)리액트 Hook 장단점

    ref)Hook의 개요

태그:

카테고리:

업데이트:

댓글남기기