React.js Custom Hooks

강정우·2023년 1월 10일
0

react.js

목록 보기
26/45
post-thumbnail

Custom Hook

  • 결국 정규함수와 똑같다. 내장 훅이라든지, useState와 같은것과 마찬가지로 말이다.
    차이점은 안에 state를 설정할 수 있는 로직을 포함한다는 것이다.
    또한 커스텀 훅은 다른 Custom Hook을 포함한 다른 리액트 훅을 사용할 수 있다.
    따라서, useState나 useReducer를 통해 관리하는 리액트 state를 활용할 수 있다.
  1. 커스텀 훅을 통해, 다른 컴포넌트에서 사용할 수 있는 로직을 커스텀 훅으로 아웃소싱할 수 있으며, 이를 통해 다양한 컴포넌트에서 호출이 가능하다.

  2. 정규 함수와 특수 함수의 관계와 같이 커스텀 훅 함수에서는 리액트 훅과 다른 훅을 사용할 수 있다.

언제?

  • 주로 중복된 코드를 리팩토링할 때 사용한다.
  • 예를 들어 BackwardCounter가 있고 ForwardCounter가 있다. 두 코드의 다른 점은 이름과 - => +로 바뀌는 것 뿐이다.
import { useState, useEffect } from 'react';

import Card from './Card';

const BackwardCounter = () => {
  const [counter, setCounter] = useState(0);			// <== from here

  useEffect(() => {
    const interval = setInterval(() => {
      setCounter((prevCounter) => prevCounter - 1);
    }, 1000);

    return () => clearInterval(interval);
  }, []);												// <== to there

  return <Card>{counter}</Card>;
};

export default BackwardCounter;
  • 이럴 때 우리가 custom hook 으로 처리하려고 하는 것이다. 이때 문제는 우리의 코드에 리액트 훅이 내포되어있고 원래는 다른 함수에서 리액트 훅을 사용하는 것은 불가능 하지만 커스텀 훅은 사용 가능하다.

어떻게?

  1. hooks란 폴더를 만들자 그리고 그 안에 use-뭐뭐뭐 라고 원하는 이름의 파일을 만들자

  • 이때 use라고 시작해야하는 이유는 저 파일안의 함수 이름의 규칙이 있기 때문이다.
  1. 이때 반드시 함수의 이름은 use-- 접두어가 붙어야한다.
  • 리액트에게 이 함수가 custom hook임을 알려주며 이는 리액트가 해당 함수를 "훅의 규칙"에 따라 사용하겠다고 보장해주는 것이다. 즉, 이 커스텀 훅을 내장 훅과 같은 방식으로 쓰겠다는 것이다.

  • use- 접두어는 리액트가 요구하는 것으로 만약 그렇지 않고 리액트 훅을 커스텀 훅에서 사용하면서, 커스텀 훅을 잘못된 곳에서 사용하게 된다면 내장 훅 역시 잘못된 곳에서 쓸 수 있음을 내포하게 된다.

  • 이 것이 use로 이름이 시작하게끔 하는 이유로 이렇게 해야 리액트가 확인을 하고 프로젝트 셋업이 함수가 use로 시작하면서 훅의 규칙을 위반한 것이 발견되었을 때 경고를 보낼 수 있기 때문이다

  1. 리팩토링하고자 하는 코드의 jsx코드를 반환하는 값은 그대로 두고 리액트 훅을 사용하는 부분만 잘라서 가져온다.
import {useState, useEffect} from "react"

const useCounter = () => {
    const [counter, setCounter] = useState(0);

    useEffect(() => {
      const interval = setInterval(() => {
        setCounter((prevCounter) => prevCounter - 1);
      }, 1000);
  
      return () => clearInterval(interval);
    }, []);
  
  	return counter;
};

export default useCounter
  • 커스텀 훅도 내장 훅처럼 어떤 것이든 반환할 수 있다.
    배열도 가능하고, 객체나 숫자도 가능하다.
  1. 리팩토링 대상이었던 코드도 깔끔하게 정리해주면 된다.
import useCounter from '../hooks/use-counter';

import Card from './Card';

const ForwardCounter = () => {
  const counter = useCounter();
  return <Card>{counter}</Card>;
};

export default ForwardCounter;
  • 만약 컴포넌트 안에서 커스텀 훅을 호출하고 이 컴포넌트가, 예를 들어 어떤 state나 effect를 사용한다면, 그 state나 effect가 커스텀 훅을 사용하고 있는 컴포넌트에 묶이게 된다.

  • 즉, 커스텀 훅의 state나 effect가 해당 컴포넌트에 생성되어 존재한다는 뜻이다.
    만약에 여러 컴포넌트에서 각각 같은 커스텀 훅을 사용한다면 state나 effect를 공유하는 것이 아닌 본인의 독자적인 state와 effect가 생성되어 "tied" 된다는 뜻이다.

  1. 3. => 에서 확장하여 매개변수로 하여금 코드에 유동성을 넣어준다.
    (1) 함수를 넣는 경우
import {useState, useEffect} from "react"

const useCounter = (counterUpdateFn) => {
    const [counter, setCounter] = useState(0);

    useEffect(() => {
      const interval = setInterval(() => {
        setCounter(counterUpdateFn);
      }, 1000);
  
      return () => clearInterval(interval);
    }, [counterUpdateFn]);

    return counter;
};

export default useCounter

(2) boolean flag로 통제하는 경우

import {useState, useEffect} from "react"

const useCounter = (forwards = true) => {
    const [counter, setCounter] = useState(0);

    useEffect(() => {
      const interval = setInterval(() => {
        if(forwards){
            setCounter((prevCounter)=>prevCounter + 1);
        }else{
            setCounter((prevCounter)=>prevCounter - 1);
        }
      }, 1000);
      return () => clearInterval(interval);
    }, [forwards]);

    return counter;
};
export default useCounter
  • 또 하나 신경써야할 점은 여기에서 사용하고 있는 이 매개변수들과 의존성이다.
    이는 useEffect 함수에서 정의된 것이 아니고 또 커스텀 훅 외부에서 설정된 것도 아니다.
    대신에, 이는 매개변수로서 받게 되는 값이기 때문에 이를 의존성으로 추가해야 한다.

  • 따라서 매개변수를 의존성으로 추가하여 의존성 변경이 발생할 때마다 useEffect 함수가 재실행하게 한다.

profile
智(지)! 德(덕)! 體(체)!

0개의 댓글