리액트, React, Custom Hook

라용·2022년 10월 3일
0

위코드 - 스터디로그

목록 보기
73/100

위코드에서 공부하며 정리한 내용입니다.

배경

Hooks 이 등장하기 전에는 관심사 분리를 위해 Presentational - Container 패턴으로 로직을 담당하는 컴포넌트와 UI를 담당하는 컴포넌트를 분리해서 관리했습니다. Hooks 이 등장한 후에는 함수 컴포넌트에서도 state 와 effect, 라이프 사이클 등의 처리를 할 수 있게 되었지만 내장 hook 을 이용해 로직을 만들어 넣으면 코드가 길어져 가독성이 떨어지기도 하고 만든 로직을 하나의 컴포넌트가 아닌 다른 컴포넌트에서 사용해야 하는 경우가 생기기도 합니다. 이런 상황을 해결하기 위해 Custom hook 이 등장하게 되었습니다.

정의 및 특징

커스텀 훅(Custom Hook)은 이름이 use 로 시작하는 자바스크립트 함수입니다. 커스텀 훅을 사용하면 컴포넌트 내부의 State 와 Effect 를 분리해 사용할 수 있고, 리액트 컴포넌트를 여러 Hook의 조합으로 개발하게 됩니다. 로직을 독립적인 함수로 분리함으로써 하나의 로직을 여러 곳에서 반복적으로 재사용할 수 있게 됩니다.

사용 예시

아래 코드는 UserStatus 라는 컴포넌트고, 사용 상태 변경이라는 버튼을 누르면 현재 사용자의 상태가 사용 중, 사용 안 함으로 변경됩니다.

// UserStatus.js (예시 코드)

import React, { useState } from 'react';

const UserStatus = () => {
  const [isActive, setIsActive] = useState(false);

  const handleToggle = () => {
    setIsActive((prev) => !prev);
  };

  return (
    <>
      <h1>현재 사용자의 상태입니다.</h1>
      <span>{isActive ? '사용 중' : '사용 안 함'}</span>
      <button onClick={handleToggle}>사용 상태 변경</button>
    </>
  );
};

export default UserStatus;

위 코드는 그렇게 길지 않지만 커스텀 훅을 연습하기 위해 로직과 UI 를 분리해보면

// ./UserStatus.js (예시 코드)

import React, { useState } from 'react';

const useToggle = (initialValue = false) => {                    
  const [state, setState] = useState(initialValue);               
  const handleToggle = () => {                                    
    setState((prev) => !prev);
  };
  return [state, handleToggle];                                   
};

const UserStatus = () => {                                      
  const [isActive, changeStatus] = useToggle();                  
  return (
    <>
      <h1>현재 사용자의 상태입니다.</h1>
      <span>{isActive ? '사용 중' : '사용 안 함'}</span>              
      <button onClick={changeStatus}>사용 상태 변경</button>
    </>
  );
};

export default UserStatus;

로직 부분을 살펴보면, useToggle 함수에 매개변수로 initialValue 를 설정하고 기본값을 false 로 할당합니다. useState 를 사용해 state에 매개변수를 할당합니다. handleToggle 함수를 생성해 해당 함수가 호출되면 기존 state 의 반대 값이 state 에 할당되도록 구현합니다. useToggle 함수에서 구현한 state 와 handleToggle 함수를 배열로 반환합니다.

이제 UI 를 담당하는 UserStatus 컴포넌트를 살펴보면, useState 를 사용했던 것처럼 useToggle 이라는 함수를 호출해서 isActive 와 changeStatus 에 useToggle 의 반환 값을 각각 할당합니다. 그리고 할당된 값으로 UI 를 구현합니다.

이렇게 커스텀 훅을 만들어 로직과 UI를 분리할 수 있습니다. 하지만 각각의 코드가 길어진다면 코드 가독성이 좋지 않고 두 가지 모두를 관리하는 것은 비효율적입니다. 여기서 더 나아가 로직과 UI 를 분리해서 관리한다면 아래와 같이 분리할 수 있습니다.

// ./useToggle.js (로직 부분 예시 코드)

import { useState } from 'react';

const useToggle = (initialValue = false) => {
  const [state, setState] = useState(initialValue);

  const handleToggle = () => {
    setState((prev) => !prev);
  };

  return [state, handleToggle];
};

export default useToggle;
// ./UserStatus.js (UI 부분 예시 코드)

import React from 'react';
import useToggle from './useToggle';

const UserStatus = () => {
  const [isActive, changeStatus] = useToggle();

  return (
    <>
      <h1>현재 사용자의 상태입니다.</h1>
      <span>{isActive ? '사용 중' : '사용 안 함'}</span>
      <button onClick={changeStatus}>사용 상태 변경</button>
    </>
  );
};

export default UserStatus;

이렇게 useToggle 을 만들어 두면 useState 를 사용한 것처럼 import 해서 사용할 수 있습니다. 모든 경우 이런 식의 분리가 권장되는 것은 아닙니다. 추상화가 필요한 경우와 아닌 경우를 잘 판단해 분리해야 합니다.

그 외 사항

커스텀 훅의 이름은 use 로 시작되어야 합니다.
Hook 안에 다른 Hook 을 호출할 수 있습니다. (중첩 호출 가능)
같은 Hook 이라도 각각의 state 는 독립적으로 관리됩니다.
별도로 만든 커스텀 훅 파일을 공통으로 사용한다면 src 폴더에 hooks 폴더를 만들어서 따로 관리합니다.

profile
Today I Learned

0개의 댓글