minghxx.blog
  • [처음 만난 리액트] section 7. Hooks
    2024년 03월 27일 07시 21분 59초에 업로드 된 글입니다.
    작성자: 민발자
    728x90

    1. Hooks의 개념과 useState, useEffect

    1) Hook이란?

    hook이란 함수 컴포넌트에 클래스 컴포넌트 기능(state, lifecycle)을 지원하기 위해 나온 것

    리액트의 state와 생명주기 기능의 갈고리를 걸어 원하는 시점에 정해진 함수를 실행되도록 만든 것 → Hook

    use---라고 명명해서 사용

     

    2) useState

    state를 사용하기 위한 hook

     

    🔎 useState 사용법

    버튼을 클릭하면 카운트를 증가하고 카운트를 보여주는 컴포넌트

    함수 컴포넌트에서 useState를 사용하지 않을 때 예제

    버튼 클릭 시 카운트가 증가하지만 재렌더링이 일어나지 않아 증가되는 값을 보여줄 수 없음

    useState 선언
    함수 컴포넌트에서 useState 사용 예제

    버튼을 클릭하면 setCount 함수를 호출해 카운트가 증가하고 컴포넌트가 재렌더링되면서 화면에 새로운 카운트 값을 보여줌

     

    🔎 useState 주의점

    클래스 컴포넌트에서는 setState 함수 하나로 모든 state를 관리할 수 있지만

    함수 컴포넌트에서는 변수마다 set함수가 필요

     

    3) useEffect

    side effect를 수행하기 위한 hook

     

    🔎 Side Effect

    리액트에서는 서버에서 데이터를 받아오거나 수동으로 DOM을 변경하는 등의 작업 의미

    → 다른 컴포넌트에 영향을 미칠 수 있고, 렌더링 중에는 작업이 완료될 수 없음

    → 렌더링이 끝난 이후에 실행되어야 함

    → 클래스 컴포넌트의 생명주기 함수와 동일한 기능을 제공

     

    🔎 useEffect 사용법

    의존성 배열 : 해당 이펙트가 의존하고 있는 배열, 배열의 값이 하나라도 변경되면 이펙트 함수 실행됨

    일반적으로 처음 컴포넌트가 렌더링 된 이후와 업데이트로 인해 재렌더링 이후 실행

    → mount와 unmount에만 실행 : 빈 배열을 넣어주면 됨

    → 의존성 배열 생략 : 컴포넌트가 업데이트될 때마다 실행

     

    2. useMemo, useCallback, useRef

    1) useMemo

    Memoized value를 리턴하는 Hook

    memoization 개념을 이용해 다시 렌더링 될 때마다 연산량이 높은 작업을 반복하는 것을 피해 렌더링 속도를 높일 수 있음

     

    🔎 Memoizationn

    최적화를 위한 개념연산

    연산량이 많이 드는 함수의 호출결과를 저장해 두었다가 같은 입력값으로 호출할 경우 이전에 저장해 놨던 호출 결과를 바로 반환

    memoization 된 값을 Memoized value라고 함

     

    🔎 useMemo 사용법

    의존성 배열에 들어있는 변수가 변했을 경우에만 새로 함수 호출, 동일한 변수를 사용할 경우 기존 함수의 결괏값을 반환

    매 렌더링마다 실행되기 때문에 의미가 없음
    마운트 이후에는 값이 변경되지 않음, 마운트 시점에만 한번 값을 계산할 때 사용

     

    🔎 useMemo 주의점

    렌더링이 일어나는 동안 실행됨

    렌더링이 일어나는 동안 작동하면 안되는 코드를 넣으면 안 됨

    서버에서 데이터를 받아오거나 수동으로 DOM을 변경하는 작업 등은 렌더링이 실행되는 동안 작동하면 안 됨 → useMemo대신 useEffect 사용

     

    2) useCallback

    의존성 배열이 변경될 때만 함수를 새로 정의해 반환

    useMemo와 유사하지만 값이 아닌 함수를 반환

    동일한 역할을 하는 useCallback과 useMemo

     

    🔎 useCallback 사용법

     

    3) useRef

    레퍼런스를 사용하기 위한 Hook

    레퍼런스 객체를 반환

     

    🔎 Reference

    특정 컴포넌트에 접근할 수 있는 객체

     

    🔎 useRef 사용법

    초깃값으로 초기화된 레퍼런스를 반환

    초깃값이 null인 경우 refObject.current 값이 nul인 객체 반환

    refObject.current → 현재 참조하고 있는 Element

    반환된 레퍼런스 객체는 컴포넌트가 마운트 해제 전까지 유지

    클릭 시 마운트 된 inputElem에 접근하여 focus 함수 호출

     

    🔎 useRef 주의점

    내부의 데이터가 변경되었을 때 별도로 알리지 않음

    → 돔 노드의 변화를 알기 위해 callback ref 사용

     

    3. Hook의 규칙과 Custom Hook 만들기

    1) Hook의 규칙

    최상위 레벨에서만 호출

    반복문이나 조건문 또는 중첩된 함수들 안에서 호출하면 안 됨

    컴포넌트가 렌더링 될 때마다 매번 같은 순서로 호출되어야 함

    다수의 useState, useEffect에 호출해서 state를 올바르게 관리 가능

     

    리액트 함수 컴포넌트에서만 호출

    자바스크립트 함수에서 사용 불가, 리액트 함수 컴포넌트나 커스텀 Hook에서만 가능

     

    잘못된 사용법

    조건이 참일 경우에만 useEffect 호출, 조건문의 결과에 따라 Hook의 호출이 결정되므로 잘못된 사용법

     

    2) Custom Hook 만들기

    이름이 use로 시작하고 내부에서 다른 Hook을 호출하는 하나의 자바스크립트 함수

    여러 컴포넌트에서 반복적으로 사용되는 로직을 Hook으로 만들어 재사용 

    여러 개의 컴포넌트에서 사용 시 컴포넌트 내부에 있는 모든 state와 effects는 전부 분리되어 있음

    → 각 custom Hook 호출에 대해서 분리된 state를 얻게 됨

    각 custom Hook 호출 또한 완전히 독립적임

    Hook 사이에서 데이터를 공유하기 위해선 파라미터로 공유

     

    🔎 custom Hook을 만들어야 하는 상황

    접속여부에 따라 텍스트로 반환하는 코드와 접속 상태를 색으로 보여주는 컴포넌트

    useState, useEffect 부분이 동일 → custom Hook으로 추출가능

     

    🔎 custom Hook으로 추출하기

    중복되는 부분을 useUserStatus라는 커스텀 훅으로 추출

     

    🔎 custom Hook 사용하기

    useUserStatus

     

    4. Hooks 사용해보기

    📃 useCounter.jsx

    import React, { useState } from 'react';
    
    function useCounter(initialValue) {
      const [count, setCount] = useState(initialValue);
    
      const increaseCount = () => setCount((count) => count + 1);
      const decreaseCount = () => setCount((count) => Math.max(count -1 , 0));
    
      return [count, increaseCount, decreaseCount];
    }
    
    export default useCounter;

    카운트 기능을 가진 custome hook을 만들어 어떤 함수 컴포넌트에서든지 카운트 기능을 사용 가능

     

     

    📃 Accommodate.jsx

    useCounter custome hook을 이용해 카운트 기능 사용

    카운트가 최대 용량을 초과하면 경고 문구가 표시되고 더 이상 입장이 불가

    useEffect 동작 방식 확인 위해 의존성 배열 없이, 있이 두 개 사용

    import React, { useEffect, useState } from 'react';
    import useCounter from './useCounter';
    
    const MAX_CAPACITY = 10;
    
    function Accommodate(props) {
      const [isFull, setIsFull] = useState(false);
      const [count, increaseCount, decreaseCount] = useCounter(0);
    
      useEffect(() => {
        console.log("======================");
        console.log("useEffect() is called.");
        console.log(`isFull: ${isFull}`);
      });
    
      useEffect(() => {
        setIsFull(count >= MAX_CAPACITY);
        console.log(`Current count value: ${count}`);
      }, [count]);
    
      return (
        <div style={{ padding: 16 }}>
          <p>{`총 ${count}명 수용했습니다.`}</p>
    
          <button onClick={increaseCount} disabled={isFull}>
            입장
          </button>
          <button onClick={decreaseCount}>
            퇴장
          </button>
    
          {isFull && <p style={{ color: "red" }}>정원이 가득찼습니다.</p>}
        </div>
      );
    }
    
    export default Accommodate;

     

    📃 index.js

    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import './index.css';
    import reportWebVitals from './reportWebVitals';
    import Accommodate from './chapter_07/Accommodate';
    
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
      <React.StrictMode>
        <Accommodate />
      </React.StrictMode>
    );
    reportWebVitals();

     

    📊 결과

    입장버튼을 누르면서 count 값이 변경

    의존성 배열이 없는 useEffect는 컴포넌트가 업데이트되어 호출되고 의존성 배열이 있는 useEffect는 카운트 값이 변경되어 호출

    최대 인원까지 추가 시 카운트 값이 더 이상 변하지 않기 때문에 의존성 배열이 있는 useEffect는 호출되지 않음

     

    728x90
    댓글