React) Nomad 실전형 리액트 훅(Custom) 내용 정리해보기

2024. 3. 16. 16:48개발

  • Nomad 선생님의 강의를 듣고 예시와 각각의 개념에 대해서 정리해보기로 하였습니다.
  • 해당 영상을 통해 유용한 Hook들을 알게 되었고, 기존에 많이 사용하는 useRef, useState, useEffect 에 대한 개념을 더 잘 이해하게 된 것 같습니다.
  • 기존에 이러한 내용을 모르고 만든 부분들에서 개선점을 확인할 수 있었고, 초보자에게 유용한 내용이였습니다.

그래서 관련 내용에 대한 개념이랑 예시 코드들을 정리해봤습니다.

Custom Hook 이란

정의

Custom Hook은 React에서 제공하는 기본 Hook을 조합하거나, 특정 작업을 위한 추가 로직을 포함하여 사용자가 직접 만든 재사용 가능한 Hook입니다.

이를 통해 컴포넌트 간에 상태 관련 로직을 쉽게 공유할 수 있게 되며, 로직을 캡슐화하고 재사용할 수 있는 방법을 제공합니다.

특징

React의 기본 Hook(예: useState, useEffect, useContext 등)은 상태 관리, 사이드 이펙트 처리, Context API 사용 등 다양한 React 기능을 함수 컴포넌트 내에서 사용할 수 있도록 해줍니다.

  • 재사용성: Custom Hook을 통해 컴포넌트 간에 공통적으로 사용되는 상태 관리 로직이나 사이드 이펙트 로직을 재사용할 수 있습니다.
  • 캡슐화: 관련된 로직을 하나의 Hook으로 묶어 관리할 수 있으며, 이를 통해 코드의 가독성과 유지보수성이 향상됩니다.
  • 모듈성: 각 Custom Hook은 독립적인 모듈로서 기능을 수행하므로, 필요에 따라 프로젝트의 다른 부분에서도 쉽게 재사용할 수 있습니다.
  • 구성 가능성: 기본 Hook들을 조합하고 필요에 따라 매개변수를 전달하여 다양한 방식으로 Custom Hook을 구성할 수 있습니다.

네이밍 규칙

Custom Hook의 이름은 use로 시작해야 하며, 이는 Hook의 사용 규칙을 따르는 동시에, React 내부에서 Hook이라는 것을 식별하는 데 도움이 됩니다.

Custom Hook을 사용함으로써, 개발자는 보다 선언적이고 명확한 코드를 작성할 수 있게 되며, 애플리케이션의 전반적인 품질과 개발 속도를 향상시킬 수 있습니다.

만드는 이유

  1. 로직의 재사용: 다양한 컴포넌트에서 유사한 로직(데이터 가져오기, 이벤트 리스너 설정 등)을 사용할 때, 사용자 정의 훅을 통해 이를 재사용할 수 있습니다.
  2. 복잡성 감소: 복잡한 상태 로직을 컴포넌트 밖으로 분리하여, 컴포넌트 자체를 더 단순하고 이해하기 쉽게 만들 수 있습니다.
  3. 가독성 향상: 비즈니스 로직을 컴포넌트로부터 분리함으로써, 코드의 가독성을 높이고, 더 명확하게 의도를 전달할 수 있습니다.
  4. 유지보수 용이: 공통 로직을 한 곳에서 관리함으로써, 코드 변경 시 다른 여러 컴포넌트에 걸쳐 있는 로직을 일일이 수정하는 대신, 한 곳에서만 수정하면 되므로 유지보수가 용이해집니다.

대표 예시

  1. useInput: 입력 필드의 값을 관리하고 유효성 검사를 수행하는 훅.
  2. useTabs: 여러 탭 간의 전환을 관리하는 훅.
  3. useFetch: 네트워크 요청을 보내고 응답 데이터를 관리하는 훅.
  4. useToggle: boolean 상태를 토글하는 로직을 간단하게 관리하는 훅.
  5. useForm: 폼 입력 및 제출 관리를 위한 훅, 유효성 검사와 폼 제출 처리를 포함.
  6. useLocalStorage: Local Storage에 데이터를 저장하고 관리하는 훅.
  7. useEventListener: 이벤트 리스너를 추가하고 제거하는 로직을 캡슐화한 훅.
  8. useInterval/useTimeout: setInterval과 setTimeout을 React 생명주기에 맞게 관리하는 훅.

React Hooks

  • useInput
  • useTabs

useInput 알아보기

개념

useInput은 React에서 입력 필드(input, textarea 등)의 상태를 관리하기 위해 사용되는 사용자 정의 훅(custom hook)입니다. 이 훅을 사용하면 입력 필드의 값(value)과 이벤트 핸들러를 쉽게 관리할 수 있으며, 컴포넌트 코드를 더 깔끔하고 재사용 가능하게 만들 수 있습니다.

기본 구조

useInput 훅은 일반적으로 입력 필드의 현재 값과 이 값을 업데이트하는 함수를 반환합니다. 추가적으로, 입력값에 대한 간단한 유효성 검사(validation)를 포함할 수도 있습니다. 아래는 useInput 훅의 기본적인 구조를 나타낸 예시입니다:

import { useState } from 'react';

function useInput(initialValue) {
  const [value, setValue] = useState(initialValue);

  const handleChange = (e) => {
    setValue(e.target.value);
  };

  return [value, handleChange];
}​
 

사용 예시

이 코드는 React에서 사용자 정의 훅(useInput)을 사용하여 입력 필드의 상태 관리와 유효성 검사를 구현하는 예시입니다. useInput 훅은 초기 값(initialValue)과 유효성 검사 함수(validator)를 매개변수로 받아, 입력 값의 상태(value)와 이 상태를 업데이트하는 함수(onChange)를 반환합니다.

  • 초기 값 설정: useInput 훅은 초기 값을 useState를 통해 상태로 관리합니다. 이 초기 값은 훅을 사용할 때 설정할 수 있습니다.
  • 변경 이벤트 핸들러: 입력 필드에 입력이 있을 때마다 onChange 함수가 호출됩니다. 이 함수 내에서는 유효성 검사 함수를 호출하여 입력 값이 유효한지 검사합니다.
  • 유효성 검사: validator 함수가 정의되어 있고, function 타입이라면, 이 함수를 호출하여 현재 입력 값의 유효성을 검사합니다. validator 함수는 입력 값이 유효하면 true, 그렇지 않으면 false를 반환해야 합니다.
  • 상태 업데이트: validator 함수의 결과가 true일 경우, 즉 입력 값이 유효할 때만 입력 값의 상태를 업데이트합니다.
import React, { useState } from "react";

import "./styles.css";

const useInput = (initialValue, validator) => {
  const [value, setValue] = useState(initialValue);
  const onChange = (e) => {
    const {
      target: { value },
    } = e;
    let willUpdate = true;
    if (typeof validator === "function") {
      willUpdate = validator(value);
    }
    if (willUpdate) {
      setValue(value);
    }
  };
  return { value, onChange };
};

export default function App() {
  const maxLen = (value) => value.length <= 10;
  const minLen = (value) => value.length >= 5;
  const name = useInput("Mr.", maxLen);
  return (
    <div className="App">
      <h1>Hello</h1>
      <input
        placeholder="Enter something"
        value={name.value}
        onChange={name.onChange}
      />
    </div>
  )
}

useTabs 알아보기

개념

useTabs는 React에서 탭 기능을 구현할 때 사용하는 사용자 정의 훅(custom hook)입니다. 이 훅을 사용하면, 여러 탭 중에서 현재 선택된 탭의 상태를 관리하고, 탭을 전환하는 함수를 쉽게 만들 수 있습니다. useTabs 훅은 특히 사용자 인터페이스에 탭이 여러 개 있고, 각 탭마다 다른 컨텐츠를 보여줘야 할 때 유용합니다.

기본 구조

useTabs 훅은 초기에 선택된 탭의 인덱스(initialTab)와 탭에 대한 정보를 담은 배열(allTabs)을 매개변수로 받습니다. 이 훅은 현재 선택된 탭의 정보와 탭을 전환하는 함수를 반환합니다.

import { useState } from 'react';

function useTabs(initialTab, allTabs) {
  const [currentIndex, setCurrentIndex] = useState(initialTab);
  
  if (!allTabs || !Array.isArray(allTabs)) {
    return;
  }
  
  return {
    currentItem: allTabs[currentIndex],
    changeItem: setCurrentIndex,
  };
}
 

사용 예시

  • 탭 상태 관리: useState를 사용하여 현재 선택된 탭의 인덱스를 상태로 관리합니다. 이는 사용자가 탭을 클릭할 때마다 업데이트됩니다.
  • 탭 변경 기능: 사용자가 특정 탭을 클릭할 때 실행될 changeItem 함수를 제공합니다. 이 함수는 클릭된 탭의 인덱스를 setCurrentIndex를 통해 업데이트함으로써 탭을 변경합니다.
import React, { useState } from "react";
const content = [
  {
    tab: "Section 1",
    content: "I'm the content of the Section 1",
  },
  {
    tab: "Section 2",
    content: "I'm the content of the Section 2",
  },
];

const useTabs = (initialTab, allTabs) => {
  if (!allTabs || !Array.isArray(allTabs)) {
    return;
  }
  const [currentIndex, setCurrentIndex] = useState(initialTab);
  return {
    currentItem: allTabs[currentIndex],
    changeItem: setCurrentIndex,
  };
};

export default function App() {
  const { currentItem, changeItem } = useTabs(0, content);
  return (
    <div className="App">
      {content.map((section, index) => (
        <button onClick={() => changeItem(index)}>{section.tab}</button>
      ))}
      <div>{currentItem.content}</div>
    </div>
  );
}

useEffect 알아보기

개념

useEffect는 React의 Hook 중 하나로, 함수 컴포넌트 내에서 사이드 이펙트(side effects)를 수행할 수 있게 해줍니다. 사이드 이펙트는 데이터 fetching, 구독(subscriptions) 설정, 수동으로 React 컴포넌트의 DOM을 수정하는 작업 등을 포함할 수 있습니다. 기본적으로 useEffect는 컴포넌트가 렌더링될 때마다 사이드 이펙트를 수행합니다.

더 쉽게 설명한 예시를 보면 다음과 같다.

상상해 보세요, 당신이 한 카페의 바리스타이고, 손님이 들어올 때마다 커피를 준비하는 일을 맡고 있습니다. 손님이 주문할 때마다 커피를 만들고, 손님이 떠날 때는 테이블을 정리하는 거죠. 여기서 손님이 주문하는 행동을 감지하고 커피를 만드는 과정이 바로 `useEffect`가 하는 일과 비슷합니다. 컴퓨터 프로그램에서 `useEffect`'특정한 조건이나 상황이 발생했을 때 어떤 작업을 자동으로 실행하게 만드는 코드'라고 볼 수 있습니다. 예를 들어, 웹 페이지에 들어갔을 때 자동으로 뉴스를 업데이트 하거나, 어떤 정보를 서버에서 불러오는 작업을 예로 들 수 있죠. 그리고 웹 페이지를 떠날 때, 저장되지 않은 정보를 저장하라는 알림을 주는 등의 '청소' 작업도 설정할 수 있습니다. 이렇게 `useEffect`는 프로그램이 특정한 상태일 때 자동으로 작업을 수행하도록 설정할 수 있게 해줍니다. 마치 바리스타가 손님이 주문할 때 커피를 만들고, 손님이 떠날 때 테이블을 정리하는 것처럼요. 이를 통해 프로그램이 더욱 유동적이고, 사용자의 행동에 반응적으로 작동하게 만들 수 있습니다.

사이드 이펙트란?

사이드 이펙트(side effect)는 프로그래밍에서 어떤 함수나 표현식이 '본래의 목적 외에 추가적인 효과'를 일으키는 현상을 말해요. 주로 다음과 같은 상황에서 발생합니다:

  1. 외부 상태 변경: 함수가 전역 변수를 변경하거나, 객체의 멤버를 변경하는 등의 외부 상태를 변경할 때.
  2. 입출력 작업: 파일 시스템이나 데이터베이스에 접근하거나, 네트워크 요청을 하는 등 외부 시스템과의 입출력 작업을 수행할 때.
  3. DOM 조작: 웹 애플리케이션에서 DOM을 직접 조작하여 화면에 변화를 주는 행위.
  4. 콘솔 로깅: 디버깅을 위해 콘솔에 로그를 출력하는 행위.

기본 구조

useEffect(() => {
  // 여기에 사이드 이펙트 로직을 작성합니다.
}, [dependencies]);
# useEffect(function,deps)
  • 첫 번째 인자: 사이드 이펙트를 수행하는 함수입니다. 이 함수는 컴포넌트가 렌더링될 때마다 실행됩니다.
  • 두 번째 인자: 의존성 배열(dependencies array)입니다. 이 배열에 명시된 값들 중 하나라도 변경될 경우, useEffect 내의 함수가 실행됩니다. 배열이 비어있다면, 컴포넌트가 마운트될 때 딱 한 번만 실행됩니다.

componentDidMount, componentWillUnmount, componentDidUpdate 란?

React에서 componentDidMount, componentWillUnmount, componentDidUpdate는 컴포넌트의 라이프사이클 메소드에 해당합니다. 이 메소드들은 클래스 컴포넌트에서 사용되며, 컴포넌트가 생성되고 업데이트되고 제거되는 생명 주기 동안 특정 작업을 수행할 때 사용됩니다. 각각의 메소드는 다음과 같은 목적으로 사용됩니다:

  1. componentDidMount: 이 메소드는 컴포넌트가 처음으로 DOM에 마운트(렌더링)된 직후에 호출됩니다. 네트워크 요청을 보내 데이터를 불러오거나, 이벤트 리스너를 설정하는 등 초기화 작업을 수행하기에 적합한 시점입니다. 클래스 컴포넌트에서 단 한 번만 호출되며, 컴포넌트가 처음으로 화면에 나타날 때 필요한 작업을 설정할 때 사용됩니다.
  2. componentWillUnmount: 컴포넌트가 DOM에서 제거되기 직전에 호출됩니다. componentDidMount에서 설정한 이벤트 리스너를 제거하거나, 타이머를 정리하는 등의 정리 작업을 수행하기에 적합한 시점입니다. 이 메소드는 컴포넌트의 생명 주기에서 단 한 번만 호출되며, 리소스 누수를 방지하기 위한 정리 작업을 수행하는 데 사용됩니다.
  3. componentDidUpdate: 컴포넌트가 업데이트되고 나서 호출됩니다. 컴포넌트의 상태나 속성이 변경될 때마다 실행되며, 이전 속성값과 상태값을 인자로 받아 올 수 있습니다. 이 메소드는 컴포넌트의 업데이트 후에 DOM을 조작하거나, 업데이트에 따른 추가적인 요청을 보내는 등의 작업에 사용됩니다.

useEffect 훅은 이러한 라이프사이클 메소드를 함수 컴포넌트에서 사용할 수 있도록 하는 React Hook입니다. useEffect를 사용함으로써, 함수 컴포넌트 내에서 컴포넌트가 마운트될 때, 업데이트될 때, 그리고 언마운트될 때의 사이드 이펙트를 관리할 수 있게 됩니다. 이는 클래스 컴포넌트의 라이프사이클 메소드와 비슷한 기능을 제공하면서도, 보다 간결하고 직관적인 코드 작성을 가능하게 합니다.

  • componentDidMount 예시
useEffect(() => {
  // componentDidMount와 동일한 효과
  console.log('Component did mount');
}, []);
  • componentWillUnmount 예
useEffect(() => {
  return () => {
    // componentWillUnmount와 동일한 효과
    console.log('Component will unmount');
  };
}, []);
  • componentDidUpdate 예시
const [count, setCount] = useState(0);
useEffect(() => {
  // componentDidUpdate와 유사한 효과, count 상태가 변경될 때마다 실행
  console.log(`Count has been updated to ${count}`);
}, [count]); // count 상태를 의존성 배열에 추가

사용예시

useEffect 훅: useEffect는 부수 효과(side effects)를 함수 컴포넌트 내에서 실행할 수 있게 해줍니다.

이 예제에서 useEffect는 number 상태가 변경될 때마다 sayHello 함수를 실행하도록 설정되어 있습니다.

useEffect의 첫 번째 인자는 효과를 수행할 함수이며, 두 번째 인자는 의존성 배열(dependency array)입니다. 의존성 배열에 포함된 값이 변경될 때만 효과가 실행됩니다.

import React, { useEffect, useState } from "react";
export default function App() {
  const [number, setNumber] = useState(0);
  const [aNumber, setAnumber] = useState(0);
  const sayHello = () => console.log("hello");
  useEffect(() => {
    sayHello();
  }, [number]);

  return (
    <div className="App">
      <div>Hi</div>
      <button onClick={() => setNumber(number + 1)}>{number}</button>
      <button onClick={() => setAnumber(aNumber + 1)}>{aNumber}</button>
    </div>
  );
}

useTitle

개념

useTitle은 React에서 사용할 수 있는 사용자 정의 Hook으로, 문서의 제목(title)을 동적으로 변경하는 데 사용됩니다. 이 Hook을 사용하면 컴포넌트의 생명주기에 따라 브라우저의 탭 제목을 쉽게 업데이트할 수 있습니다.

기본 구조

  1. useState를 사용하여 제목 상태를 관리합니다.
  2. useEffect를 사용하여 컴포넌트가 렌더링될 때 문서의 제목을 업데이트합니다.
const useTitle = (initialTitle) => {
  const [title, setTitle] = useState(initialTitle);

  useEffect(() => {
    const htmlTitle = document.querySelector("title");
    htmlTitle.textContent = title;
  }, [title]);

  return setTitle;
};
 

사용 예시

이 예제에서 useTitle Hook은 초기 제목을 매개변수로 받아 상태로 관리합니다. useEffect Hook을 사용해 해당 제목 상태가 변경될 때마다 문서의 제목도 함께 업데이트합니다. setTimeout을 사용해 5초 후에 제목을 "Home"으로 변경하는 예를 보여주고 있습니다. 이러한 방식으로 컴포넌트 내에서 동적으로 문서 제목을 관리할 수 있습니다.

import React, { useEffect, useState } from "react";

const useTitle = (initialTitle) => {
  const [title, setTitle] = useState(initialTitle);
  const updateTitle = () => {
    const htmlTtile = document.querySelector("title");
    htmlTtile.innerText = title;
  };

  useEffect(updateTitle, [title]);
  return setTitle;

};

  

export default function App() {
  const titleUpdater = useTitle("Loading...");
  setTimeout(() => titleUpdater("Home"), 5000);
  return <div className="App"></div>;

}

useRef 알아보기

개념

useRef는 React의 Hook 중 하나로, 주로 두 가지 목적으로 사용됩니다:

  1. DOM 요소에 직접 접근하기 위해: React에서 DOM 요소를 직접 조작하거나 접근해야 할 경우 사용합니다. 예를 들어, 입력 필드에 포커스를 주거나, 동적으로 생성된 요소의 크기를 읽어야 할 때 유용합니다.
  2. 렌더링 사이에 값을 "기억"하기 위해: 컴포넌트의 라이프사이클 동안 유지되어야 하는 값을 저장할 때 사용합니다. 이 값은 컴포넌트가 리렌더링되더라도 유지되며, useRef로 생성된 값의 변경이 리렌더링을 유발하지 않는 것이 특징입니다.

기본 구조

여기서 initialValue는 ref 객체의 초기값으로 설정되며, 이 값은 .current 속성을 통해 접근할 수 있습니다. initialValue는 선택 사항이며, 설정하지 않을 경우 기본값은 null입니다.

 
const refContainer = useRef(initialValue);

예시

  • 컴포넌트가 리렌더링되어도 카운트 값을 유지하는 예시입니다.
import React, { useRef } from 'react';
function Counter() {
  const renderCount = useRef(0);
  renderCount.current = renderCount.current + 1;
  return (
    <div>
      <p>렌더링 횟수: {renderCount.current}</p>
    </div>
  );
}
export default Counter;

리렌더링이 되지 않는 이유

useRef가 리렌더링을 유발하지 않는 이유는, useRef로 생성된 객체가 React의 렌더링 흐름 밖에서 관리되기 때문입니다. useRef는 .current 프로퍼티를 가진 일반 JavaScript 객체를 반환하며, 이 객체의 .current 프로퍼티를 변경해도 React의 상태 변경 시스템이 관여하지 않습니다.

React 컴포넌트의 리렌더링은 주로 상태(useState, useReducer 등)의 변경이나 props의 변경에 의해 유발됩니다. 이와 달리, useRef를 사용하여 저장된 값은 컴포넌트의 상태나 props로 관리되지 않으며, 따라서 이 값이 변경되어도 React는 그 변경을 리렌더링의 이유로 간주하지 않습니다.

결과적으로, useRef는 값을 참조하거나 DOM 요소에 접근하기 위한 용도로 사용되며, 이 값의 변경은 컴포넌트의 뷰 상태에 직접적인 영향을 주지 않기 때문에 리렌더링을 유발하지 않습니다. 이러한 특성 덕분에 useRef는 컴포넌트가 리렌더링되어도 유지되어야 하는 값을 저장하거나, DOM 요소에 직접적으로 접근해야 할 때 유용하게 사용됩니다.

→ 이런 이유로 useState와는 차이가 있

useClick 알아보기

개념

useClick은 React에서 사용할 수 있는 사용자 정의 Hook으로, 특정 요소에 대한 클릭 이벤트를 관리하는 데 사용됩니다. 이 Hook을 통해 클릭 이벤트 리스너를 쉽게 추가하고 제거할 수 있으며, 특정 동작을 클릭 시 실행할 수 있습니다.

기본 구조

  1. useRef를 사용하여 DOM 요소를 참조합니다.
  2. useEffect를 사용하여 컴포넌트가 마운트되었을 때 이벤트 리스너를 추가하고, 언마운트 시 이벤트 리스너를 제거합니다.
import React, { useEffect, useRef } from "react";

// useClick Hook 정의
const useClick = (onClick) => {
  const element = useRef();
  useEffect(() => {
    if (element.current) {
      element.current.addEventListener("click", onClick);
    }
    return () => {
      if (element.current) {
    element.current.removeEventListener("click", onClick);
      }
    };
  }, [onClick]);

  return element;
};

사용 예시

이 예시에서 useClick은 사용자 정의 훅(useCustom Hook)입니다. 이 훅은 클릭 이벤트가 발생했을 때 실행할 콜백 함수를 인자로 받고, 이벤트 리스너를 등록하거나 제거할 DOM 요소에 접근하기 위한 ref 객체를 반환합니다.

useEffect 사용의 중요성

useEffect 훅은 컴포넌트가 마운트될 때(컴포넌트가 화면에 나타날 때)와 언마운트될 때(컴포넌트가 화면에서 사라질 때), 그리고 컴포넌트의 상태가 업데이트될 때 부수 효과(Side Effects)를 실행하기 위해 사용됩니다.

이 예시에서 useEffect는 useClick 내부에서 사용되어, 컴포넌트 마운트 시 클릭 이벤트 리스너를 추가하고, 컴포넌트가 언마운트될 때 이벤트 리스너를 제거하는 역할을 합니다. 이 방법은 리소스 누수를 방지하고, 컴포넌트가 화면에서 사라진 후에도 이벤트 리스너가 남아있는 문제를 해결합니다.

사용 예

  • useRef 훅을 사용하여 DOM 요소에 대한 참조(ref)를 생성합니다. useRef는 .current 프로퍼티를 통해 참조된 DOM 요소에 접근할 수 있게 해줍니다.
  • useEffect 내부에서 ref.current를 사용하여 해당 DOM 요소에 클릭 이벤트 리스너를 추가합니다. 이때, 첫 번째 인자로 전달된 콜백 함수는 컴포넌트가 마운트된 직후에 실행됩니다.
  • useEffect의 반환 값으로 새로운 함수를 제공하여, 컴포넌트가 언마운트되기 직전에 클릭 이벤트 리스너를 제거합니다. 이는 리소스 누수를 방지하는 중요한 단계입니다.
  • useEffect의 의존성 배열([])을 비워두어, 이 훅이 컴포넌트의 마운트와 언마운트 시점에만 실행되도록 합니다. 의존성 배열에 변수를 추가하면 해당 변수가 변경될 때마다 useEffect 내의 코드가 실행됩니다.
import React, { useEffect, useState, useRef } from "react";
const useClick = (onClick) => {
  const ref = useRef();
  useEffect(() => {
    const element = ref.current;
    if (element) {
    // componentDidMount와 componentDidUpdate에 해당
      element.addEventListener("click", onClick);
    }
    // componentWillUnmount에 해당
    return () => {
      if (element) {
        element.removeEventListener("click", onClick);
      }
    };
  }, []);
  return ref;
};

export default function App() {
  const onClick = () => console.log("say hello");
  const title = useClick(onClick);
  return (
    <div className="App">
      <h1 ref={title}>Hi</h1>
    </div>
  );
}

useEffect 부분 재강조

  • componentDidMount에 해당: useEffect의 콜백 함수가 컴포넌트가 마운트된 직후에 실행됩니다. 이때, 클릭 이벤트 리스너를 추가합니다. 이는 컴포넌트가 처음으로 UI에 렌더링 될 때 한 번만 실행되어야 하는 초기화 작업을 처리하는 시점입니다.
  • componentDidUpdate에 해당: 이 예시에서는 의존성 배열(dependency array)이 빈 배열([])로 주어졌기 때문에, 업데이트 사이클에서는 실행되지 않습니다. 만약 의존성 배열에 특정 상태나 속성을 넣었다면, 해당 상태나 속성이 변경될 때마다 콜백 함수가 실행되어 componentDidUpdate의 역할을 수행하게 됩니다.
  • componentWillUnmount에 해당: useEffect의 클린업(cleanup) 함수는 컴포넌트가 제거되기 직전에 호출됩니다. 이 시점에서 이벤트 리스너를 제거함으로써, 필요 없어진 리소스를 정리하고 메모리 누수를 방지합니다.

이처럼 useEffect를 사용하면, 함수 컴포넌트 내에서도 클래스 컴포넌트의 생명주기 메서드와 유사한 패턴으로 사이드 이펙트를 관리할 수 있습니다.

useHover

  • useClick 과 개념이 동일하여 자세한 설명 생략
import React, { useEffect, useState, useRef } from "react";

const useHover = (onHover) => {
  const ref = useRef();
  useEffect(() => {
    const element = ref.current;
    if (element) {
      element.addEventListener("mouseenter", onHover);
    }
    return () => {
      if (element) {
        element.removeEventListener("mouseenter", onHover);
      }
    };
  }, []);
  return ref;
};

  

export default function App() {
  const onHover = () => console.log("say hello");
  const title = useHover(onHover);
  return (
    <div className="App">
      <h1 ref={title}>Hi</h1>
    </div>
  );
}

useConfirm 알아보기

개념

useConfirm은 사용자가 특정 작업을 수행하기 전에 확인을 요청하는 커스텀 훅입니다.

이는 window.confirm과 같은 네이티브 자바스크립트 함수를 사용해 사용자의 결정에 따라 지정된 콜백 함수를 실행하거나 실행하지 않도록 하는 용도로 사용됩니다.

주로 중요한 작업을 수행하기 전에 사용자의 의사를 다시 한 번 확인할 때 유용합니다.

기본구조

useConfirm 훅은 window.confirm 함수를 사용하여 사용자에게 메시지를 보여주고, 사용자가 '확인' 버튼을 클릭하면 onConfirm 함수를, '취소' 버튼을 클릭하면 onCancel 함수를 실행합니다. onConfirm과 onCancel은 함수여야 하며, 이를 통해 사용자의 응답에 따라 적절한 액션을 취할 수 있습니다.

  • message: 사용자에게 보여줄 확인 메시지입니다.
  • onConfirm: 사용자가 '확인'을 선택했을 때 실행될 함수입니다.
  • onCancel: 사용자가 '취소'를 선택했을 때 실행될 함수입니다. 이 파라미터는 선택적입니다.
const useConfirm = (message = "", onConfirm, onCancel) => {
  if (typeof onConfirm !== "function") {
    return;
  }
  if (onCancel && typeof onCancel !== "function") {
    return;
  }
  const confirmAction = () => {
    if (window.confirm(message)) {
      onConfirm();
    } else {
      onCancel && onCancel();
    }
  };
  return confirmAction;
};

사용 예시

이 코드는 useConfirm이라는 사용자 정의 훅을 사용하는 React 컴포넌트의 예입니다. useConfirm은 사용자가 중요한 작업을 수행하기 전에 확인을 요청하는 로직을 구현하기 위해 만들어진 훅입니다.

useConfirm 훅의 구조:

  • message: 사용자에게 표시할 확인 메시지입니다.
  • onConfirm: 사용자가 '확인'을 클릭했을 때 실행할 함수입니다.
  • onCancel: 사용자가 '취소'를 클릭했을 때 실행할 함수입니다.

useConfirm 훅은 window.confirm 함수를 사용하여 사용자에게 확인 요청을 합니다. window.confirm은 브라우저가 제공하는 기본 대화 상자로, 사용자에게 메시지를 표시하고 '확인' 또는 '취소' 버튼을 제공합니다.

useConfirm 훅의 로직:

  1. useConfirm 함수는 confirmAction이라는 함수를 반환합니다.
  2. confirmAction 함수는 사용자가 버튼을 클릭하면 호출됩니다.
  3. 사용자가 '확인'을 클릭하면 window.confirm 함수가 true를 반환하고, onConfirm 함수가 실행됩니다.
  4. 사용자가 '취소'를 클릭하면 window.confirm 함수가 false를 반환하고, onCancel 함수가 실행됩니다.
import React, { useEffect, useState, useRef } from "react";
const useConfirm = (message, onConfirm, onCancel) => {
  if (!onConfirm || typeof onConfirm !== "function") {
    return;
  }
  if (!onCancel || typeof onCancel !== "function") {
    return;
  }
  const confirmAction = () => {
    if (window.confirm(message)) {
      onConfirm();
    } else {
      onCancel();
    }
  };
  return confirmAction;
};

export default function App() {
  const deleteWorld = () => console.log("Deleting the world");
  const abort = () => console.log("Aborted");
  const confirmDelete = useConfirm("Are you sure?", deleteWorld, abort);
  return (
    <div className="App">
      <button onClick={confirmDelete}>Delete the world</button>
    </div>
  );
}

usePreventLeave 알아보기

개념

usePreventLeave는 사용자가 페이지를 실수로 벗어나려고 할 때 경고 메시지를 보여주는 사용자 정의 훅입니다.

이 훅은 사용자가 중요한 데이터 입력 중에 실수로 페이지를 닫거나 다른 페이지로 이동할 때 데이터 손실을 방지하기 위해 사용됩니다.

기본구조

usePreventLeave 훅은 두 개의 함수를 제공합니다 enablePrevent와 disablePrevent입니다. enablePrevent 함수를 호출하면 페이지를 벗어나려고 할 때 브라우저가 사용자에게 경고 메시지를 보여주며, disablePrevent 함수를 호출하면 이 경고 메시지를 비활성화합니다.

import React from "react";

const usePreventLeave = () => {
  const listener = (event) => {
    event.preventDefault();
    event.returnValue = ""; // 크롬에서 필요한 설정입니다.
  };
  const enablePrevent = () => window.addEventListener("beforeunload", listener);
  const disablePrevent = () => window.removeEventListener("beforeunload", listener);
  return { enablePrevent, disablePrevent };
};

export default function App() {
  const { enablePrevent, disablePrevent } = usePreventLeave();
  return (
    <div>
      <button onClick={enablePrevent}>Protect</button>
      <button onClick={disablePrevent}>Unprotect</button>
    </div>
  );
}

사용 예시

usePreventLeave 훅의 구성

  • listener 함수: 이 함수는 브라우저의 beforeunload 이벤트가 발생할 때 호출됩니다. event.preventDefault()와 event.returnValue = "";를 사용하여 페이지를 벗어나려는 동작을 차단하고, 사용자에게 경고 메시지를 표시합니다.
  • enablePrevent 함수: 이 함수는 window 객체에 beforeunload 이벤트 리스너를 추가합니다. 이 리스너는 페이지를 벗어나려고 할 때 listener 함수를 호출하여 사용자에게 경고합니다.
  • disablePrevent 함수: 이 함수는 enablePrevent 함수에 의해 추가된 beforeunload 이벤트 리스너를 제거합니다. 이를 통해 페이지를 벗어날 때 경고 메시지가 표시되지 않도록 합니다.

컴포넌트에서의 사용

App 컴포넌트에서 usePreventLeave 훅을 사용하여 enablePrevent와 disablePrevent 함수를 가져옵니다. 이 두 함수는 각각 'Protect' 버튼과 'Unprotect' 버튼에 연결되어 있습니다.

  • 'Protect' 버튼: 이 버튼을 클릭하면 enablePrevent 함수가 호출되어 페이지를 벗어나려고 할 때 사용자에게 경고 메시지가 표시됩니다.
  • 'Unprotect' 버튼: 이 버튼을 클릭하면 disablePrevent 함수가 호출되어 경고 메시지가 비활성화됩니다.

이 예시를 통해 사용자가 중요한 데이터 입력 중에 실수로 페이지를 닫거나 다른 페이지로 이동할 때 데이터 손실을 방지하는 추가적인 안전장치를 제공할 수 있습니다.

import React, { useEffect, useState, useRef } from "react";

const usePreventLeave = () => {
  const listener = (event) => {
    event.preventDefault();
    event.returnValue = "";
  };

  const enablePrevent = () => {
    window.addEventListener("beforeunload", listener);
  };

  const disablePrevent = () => {
    window.removeEventListener("beforeunload", listener);
  };

  return {
    enablePrevent,
    disablePrevent,
  };

};

export default function App() {
  const { enablePrevent, disablePrevent } = usePreventLeave();
  return (
    <div className="App">
      <button onClick={enablePrevent}>Protect</button>
      <button onClick={disablePrevent}>Unprotect</button>
    </div>
  );
}

useBeforeLeave

개념

useBeforeLeave 훅은 사용자가 웹 페이지를 벗어나기 전에 특정한 동작을 수행하도록 도와주는 커스텀 훅입니다.

이 훅은 주로 사용자가 페이지를 닫거나 다른 페이지로 넘어가려고 할 때 경고를 주거나, 사용자에게 특정 행동을 유도하기 위해 사용됩니다.

예를 들어, 폼 작성 중 페이지를 벗어나려는 사용자에게 데이터가 저장되지 않았음을 알릴 때 유용하게 사용할 수 있습니다.

기본 구조

import { useEffect } from 'react';

const useBeforeLeave = (onBefore) => {
  useEffect(() => {
    const handleLeave = (event) => {
      // 마우스가 브라우저 창을 벗어나는 방향으로 이동할 때 onBefore 함수 실행
      const { clientY } = event;
      if (clientY <= 0) {
        onBefore();
      }
    };
    document.addEventListener('mouseleave', handleLeave);
    return () => document.removeEventListener('mouseleave', handleLeave);
  }, [onBefore]);
};

사용 예시

작동 원리

  • useBeforeLeave 훅은 onBefore라는 콜백 함수를 인자로 받습니다.
  • useEffect 훅 내에서 document에 mouseleave 이벤트 리스너를 추가합니다. 이 리스너는 사용자가 마우스를 브라우저 창의 상단으로 이동시킬 때 실행됩니다.
  • 이벤트 리스너는 clientY 속성을 검사하여, 이 값이 0 이하일 경우 (즉, 마우스가 윈도우 상단을 벗어날 경우) onBefore 콜백 함수를 실행합니다.
  • 컴포넌트가 언마운트되거나, useEffect가 다시 실행될 때 기존에 등록된 이벤트 리스너를 정리합니다. 이는 리소스 누수를 방지하고, 메모리 사용을 최적화하는 데 중요합니다.
import React, { useEffect, useState, useRef } from "react";
const useBeforeLeave = (onBefore) => {
  if (typeof onBefore !== "function") {
    return "";
  }

  const handle = (event) => {
    const { clientY } = event;
    if (clientY <= 0) {
      onBefore();
    }
  };

  useEffect(() => {
    document.addEventListener("mouseleave", handle);
    return () => {
      document.removeEventListener("mouseleave", handle);
    };
  }, []);
};

  

export default function App() {
  const begForlive = () => console.log("please don't leave");
  useBeforeLeave(begForlive);
  return (
    <div className="App">
      <h1>Hello</h1>
    </div>
  );
}

useFadeIn

개념

useFadeIn은 컴포넌트의 등장 애니메이션을 처리하기 위한 커스텀 훅입니다. 특히, 요소가 서서히 나타나는 페이드-인 효과를 적용할 때 사용됩니다. 이 훅을 사용하면 CSS 애니메이션 또는 JavaScript를 직접 작성하지 않고도, 간단하게 페이드-인 효과를 구현할 수 있습니다.

기본 구조

useFadeIn 훅은 일반적으로 애니메이션의 지속 시간(duration)과 지연 시간(delay)을 인자로 받습니다. 이 훅은 스타일 객체를 반환하며, 이 객체는 opacity와 transition 속성을 포함하여 페이드-인 효과를 구현합니다.

const useFadeIn = (duration = 1, delay = 0) => {
  const element = useRef();
  
  useEffect(() => {
    if (element.current) {
      const { current } = element;
      current.style.transition = `opacity ${duration}s ease-in-out ${delay}s`;
      current.style.opacity = 1;
    }
  }, []);
  
  return { ref: element, style: { opacity: 0 } };
};

사용 예시

useFadeIn 훅의 구조

  • duration: 페이드-인 효과가 지속되는 시간입니다. 기본값은 1초입니다.
  • delay: 페이드-인 효과가 시작하기 전에 대기하는 시간입니다. 기본값은 0초입니다.
  • element: useRef를 사용하여 참조(ref)를 생성합니다. 이 ref는 훅을 사용하는 요소에 부여됩니다.

useEffect 내부에서, element.current에 접근하여 해당 요소의 스타일을 직접 조작합니다. transition 속성을 설정하여 페이드-인 효과를 위한 애니메이션을 정의하고, opacity 속성을 1로 설정하여 요소를 완전히 불투명하게 만듭니다.

이때, transition 속성에는 duration과 delay 값이 사용됩니다.

import React, { useEffect, useState, useRef } from "react";
const useFadeIn = (duration = 1, delay = 0) => {
  if (typeof duration !== "number" || typeof delay !== "number") {
    return;
  }
  const element = useRef();
  useEffect(() => {
    if (element.current) {
      element.current.style.transition = `opacity ${duration}s ease-in-out ${delay}s`;
      element.current.style.opacity = 1;
    }
  }, []);
  return { ref: element, style: { opacity: 0 } };
};
export default function App() {
  const fadeInH1 = useFadeIn(2, 1);
  const fadeInP = useFadeIn(2, 3);
  return (
    <div className="App">
      <h1 {...fadeInH1}>Hello</h1>
      <p {...fadeInP}>Bye... </p>
    </div>
  );
}

useNetwork

개념

useNetwork 커스텀 훅은 사용자의 네트워크 연결 상태를 감지하고 해당 상태에 따라 반응할 수 있게 해주는 기능을 제공합니다.

이를 통해 네트워크 연결이 변경될 때마다 특정 액션을 수행하거나 사용자에게 알림을 제공하는 등의 동작을 구현할 수 있습니다.

기본 구조

const useNetwork = (onChange) => {
  const [status, setStatus] = useState(navigator.onLine); // 초기 네트워크 상태 설정

  const handleChange = () => {
    if (typeof onChange === "function") {
      onChange(navigator.onLine);
    }
    setStatus(navigator.onLine); // 네트워크 상태 업데이트
  };

  useEffect(() => {
    window.addEventListener("online", handleChange); // 온라인 상태 감지
    window.addEventListener("offline", handleChange); // 오프라인 상태 감지

    return () => {
      window.removeEventListener("online", handleChange);
      window.removeEventListener("offline", handleChange);
    };
  }, []);

  return status; // 현재 네트워크 상태 반환
};

사용 예시

이 예시에서 useNetwork 훅은 네트워크 상태가 변경될 때마다 handleNetworkChange 함수를 호출합니다. handleNetworkChange는 네트워크가 온라인 상태로 바뀌었는지, 아니면 오프라인 상태가 되었는지에 따라 적절한 메시지를 콘솔에 출력합니다.

또한, isOnline 변수를 사용하여 현재 네트워크 상태를 화면에 표시합니다.

const useNetwork = (onChange) => {
  const [status, setStatus] = useState(navigator.onLine); // 초기 네트워크 상태 설정

  const handleChange = () => {
    if (typeof onChange === "function") {
      onChange(navigator.onLine);
    }
    setStatus(navigator.onLine); // 네트워크 상태 업데이트
  };

  useEffect(() => {
    window.addEventListener("online", handleChange); // 온라인 상태 감지
    window.addEventListener("offline", handleChange); // 오프라인 상태 감지

    return () => {
      window.removeEventListener("online", handleChange);
      window.removeEventListener("offline", handleChange);
    };
  }, []);

  return status; // 현재 네트워크 상태 반환
};

export default function App() {
  const handleNetworkChange = (online) => {
    console.log(online ? "We just went online" : "We are offline");
  };
  const isOnline = useNetwork(handleNetworkChange);

  return (
    <div className="App">
      <h1>{isOnline ? "Online" : "Offline"}</h1>
    </div>
  );
}

useScroll

개념

useScroll은 사용자가 웹 페이지를 스크롤할 때의 위치를 추적하는 커스텀 훅입니다. 이 훅을 사용하면 스크롤 위치에 따라 동적으로 UI를 변경하거나 특정 스크롤 위치에 도달했을 때 이벤트를 발생시킬 수 있습니다.

기본 구조

useScroll 커스텀 훅은 스크롤 위치를 {x, y} 객체 형태로 상태로 관리합니다.

window.pageXOffset과 window.pageYOffset을 사용하여 현재 문서의 스크롤 위치를 가져오며, 이 값을 setScrollPosition 함수를 통해 업데이트합니다.

const useScroll = () => {
  const [scrollPosition, setScrollPosition] = useState({ x: 0, y: 0 });

  const handleScroll = () => {
    setScrollPosition({ x: window.pageXOffset, y: window.pageYOffset });
  };

  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    return () => window.removeEventListener("scroll", handleScroll);
  }, []);

  return scrollPosition;
};

사용 예시

useScroll 훅의 작동 방식:

  1. useState를 사용하여 스크롤 위치의 초기 상태를 { x: 0, y: 0 }로 설정합니다. 여기서 x는 수평 스크롤 위치, y는 수직 스크롤 위치를 나타냅니다.
  2. onScroll 함수는 윈도우의 스크롤 이벤트가 발생할 때마다 호출되며, 현재 문서의 스크롤 위치(window.scrollY 및 window.scrollX)를 setState를 통해 업데이트합니다.
  3. useEffect 훅 내에서 window 객체에 scroll 이벤트 리스너를 추가합니다. 이 리스너는 컴포넌트가 마운트될 때 등록되고, 컴포넌트가 언마운트될 때 제거됩니다. 이를 통해 불필요한 이벤트 리스너가 메모리에 남아있지 않도록 관리합니다.
  4. useScroll 훅은 스크롤 상태 객체 { x, y }를 반환합니다.

App 컴포넌트:

  • useScroll 훅을 사용하여 현재의 스크롤 위치를 가져옵니다.
  • y 값(수직 스크롤 위치)을 기준으로 조건부 스타일링을 적용합니다. 사용자가 100px 이상 스크롤하면 텍스트의 색상이 빨간색으로 바뀌고, 그렇지 않으면 파란색으로 표시됩니다.
  • 이 예에서는 스크롤 위치에 따라 동적으로 스타일이 변경되는 헤더(<h1>) 요소를 렌더링합니다.
import React, { useEffect, useState, useRef } from "react";
const useScroll = () => {
  const [state, setState] = useState({
    x: 0,
    y: 0,
  });
  const onScroll = () => {
    console.log(window.scrollY);
    setState({ y: window.scrollY, x: window.scrollX });
  };
  useEffect(() => {
    window.addEventListener("scroll", onScroll);
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return state;
};
export default function App() {
  const { y } = useScroll();
  return (
    <div className="App">
      <h1 style={{ position: "fixed", color: y > 100 ? "red" : "blue" }}>
        ???
      </h1>
    </div>
  );
}

useFullscreen

개념

useFullscreen은 사용자가 특정 요소를 전체 화면으로 전환할 수 있게 해주는 커스텀 훅입니다. 이 훅을 사용하여 이미지, 비디오 또는 어떠한 DOM 요소든 전체 화면으로 만들 수 있습니다. 사용자가 전체 화면 모드를 종료하려고 할 때, 이를 감지하여 추가적인 액션을 취할 수도 있습니다.

기본 구조

useFullscreen은 사용자가 특정 요소를 전체 화면으로 전환할 수 있게 해주는 커스텀 훅입니다. 이 훅을 사용하여 이미지, 비디오 또는 어떠한 DOM 요소든 전체 화면으로 만들 수 있습니다. 사용자가 전체 화면 모드를 종료하려고 할 때, 이를 감지하여 추가적인 액션을 취할 수도 있습니다.

기본 구조:

useFullscreen은 두 가지 주요 기능을 제공합니다: 요소를 전체 화면으로 만드는 기능과 전체 화면 모드를 종료하는 기능입니다. 이를 위해, 훅은 전체 화면으로 만들고자 하는 요소의 참조(ref)와 함께 두 개의 함수를 반환합니다.

  1. 전체 화면 요청 함수(enterFullScreen): 사용자가 호출할 때 지정된 요소를 전체 화면으로 전환합니다.
  2. 전체 화면
const useFullscreen = (callback) => {
  const element = useRef();

  const triggerFull = () => {
    if (element.current) {
      element.current.requestFullscreen();
      if (callback && typeof callback === "function") {
        callback(true);
      }
    }
  };

  const exitFull = () => {
    document.exitFullscreen();
    if (callback && typeof callback === "function") {
      callback(false);
    }
  };

  return { element, triggerFull, exitFull };
};

사용 예시

  • useFullscreen 훅은 callback 함수를 매개변수로 받아, 전체 화면이 활성화되거나 비활성화될 때 호출됩니다. 이 콜백은 전체 화면의 상태(활성화/비활성화)에 따라 true 또는 false를 인자로 받습니다.
  • 훅을 사용하는 컴포넌트에서 useFullscreen을 호출하고, 전체 화면으로 만들고자 하는 요소의 참조(ref)와 두 개의 함수(triggerFull와 exitFull)를 받습니다.
  • triggerFull 함수는 사용자가 버튼을 클릭할 때 해당 요소를 전체 화면으로 전환합니다.
  • exitFull 함수는 다른 버튼을 클릭하여 전체 화면 모드에서 나올 수 있습니다.
  • onFullS 콜백 함수는 전체 화면 모드의 변화를 콘솔에 로그로 남깁니다.
import React, { useRef } from "react";

const useFullscreen = (callback) => {
  const element = useRef();
  const triggerFull = () => {
    if (element.current) {
      element.current.requestFullscreen();
      if (callback && typeof callback === "function") {
        callback(true);
      }
    }
  };
  const exitFull = () => {
    document.exitFullscreen();
    if (callback && typeof callback === "function") {
      callback(false);
    }
  };
  return { element, triggerFull, exitFull };
};

const App = () => {
  const onFullS = (isFull) => {
    console.log(isFull ? "We are full" : "We are small");
  };
  const { element, triggerFull, exitFull } = useFullscreen(onFullS);
  return (
    <div className="App" style={{ height: "1000vh" }}>
      <div ref={element}>
        <img src="https://placekitten.com/200/300" alt="cat" />
        <button onClick={triggerFull}>Make fullscreen</button>
      </div>
      <button onClick={exitFull}>Exit fullscreen</button>
    </div>
  );
};

export default App;

useNotification

개념

useNotification은 브라우저의 Notification API를 이용하여 사용자에게 알림을 표시하는 React 훅입니다. 이를 사용하면 웹 애플리케이션에서 알림을 손쉽게 만들고 제어할 수 있습니다.

기본 구조

import { useEffect } from 'react';

const useNotification = (title, options) => {
  useEffect(() => {
    if (!("Notification" in window)) {
      console.error("This browser does not support desktop notification");
      return;
    }

    const fireNotification = () => {
      if (Notification.permission !== "granted") {
        Notification.requestPermission().then((permission) => {
          if (permission === "granted") {
            new Notification(title, options);
          } else {
            console.error("User denied permission for notifications");
          }
        });
      } else {
        new Notification(title, options);
      }
    };

    fireNotification();
  }, [title, options]);
};

export default useNotification;

사용 예시

위의 예시에서는 useNotification 훅을 사용하여 "Hello, world!"라는 제목과 본문이 포함된 알림을 생성하고, 버튼 클릭 시 이 알림을 화면에 표시합니다. useNotification 훅을 호출하면 제목과 옵션을 인자로 전달하여 알림을 생성하는 함수가 반환됩니다. 이 함수를 적절한 이벤트 핸들러에 연결하여 사용하면 됩니다.

import React, { useEffect, useState, useRef } from "react";

const useNotification = (title, options) => {
  if (!("Notification" in window)) {
    return;
  }

  const fireNotif = () => {
    if (Notification.permission !== "granted") {

      Notification.requestPermission().then((permission) => {

        if (permission == "granted") {

          new Notification(title, options);

        } else {

          return;

        }

      });

    } else {

      new Notification(title, options);

    }

  };

  return fireNotif;

};

  

export default function App() {

  const triggerNotif = useNotification("Hello, world!", { body: "This is a notification from your web app", });

  return (

    <div className="App" style={{ height: "1000vh" }}>

      <button onClick={triggerNotif}>Hello</button>

    </div>

  );

}

useAxios

Axios 란?

Axios는 자바스크립트를 위한 강력한 HTTP 클라이언트 라이브러리입니다. 주로 웹 애플리케이션에서 서버로 HTTP 요청을 보내고 응답을 받아오는 데 사용됩니다.

개념

useAxios 훅은 네트워크 요청을 처리하기 위해 Axios를 활용하는 커스텀 훅입니다. 이를 사용하면 HTTP GET, POST, PUT, DELETE 등의 요청을 보내고, 서버에서 받은 응답을 처리할 수 있습니다.

기본 구조

useState를 이용한 상태 관리:

  • data: 서버에서 받아온 데이터를 저장하는 상태입니다.
  • error: 요청 중 발생한 오류를 저장하는 상태입니다.
  • loading: 데이터를 가져오는 동안 로딩 상태를 관리합니다.

useEffect를 이용한 데이터 요청 처리:

  • useEffect 훅을 사용하여 컴포넌트가 마운트되거나 업데이트될 때마다 데이터를 가져오는 비동기 함수를 실행합니다.
  • axios를 사용하여 지정된 URL에서 데이터를 가져옵니다.
  • 요청이 성공하면 setData 함수를 사용하여 데이터 상태를 업데이트하고, setLoading을 통해 로딩 상태를 false로 변경합니다.
  • 요청이 실패하면 setError 함수를 사용하여 오류 상태를 업데이트하고, 마찬가지로 로딩 상태를 false로 변경합니다.
import axios from 'axios';
import { useState, useEffect } from 'react';

const useAxios = (url, options = {}) => {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await axios(url, options);
        setData(response.data);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => {
      // cleanup 작업
    };
  }, [url, options]);

  return { data, error, loading };
};

export default useAxios;

사용 예시

  1. useAxios 커스텀 훅 설명:
    • useAxios는 Axios를 사용하여 데이터를 가져오는 데 도움을 주는 커스텀 훅입니다.
    • opts는 Axios 요청에 필요한 옵션을 포함하는 객체입니다. 여기서는 url 속성이 필수입니다.
    • axiosInstance는 Axios 인스턴스를 사용하여 요청을 보내는 데 사용됩니다. 기본값은 defaultAxios로 설정되어 있습니다.
    • state는 현재 데이터 상태를 나타냅니다. loading은 데이터 로딩 상태, error는 오류 상태, data는 받아온 데이터를 나타냅니다.
    • trigger는 useEffect를 실행시키기 위한 상태 변수입니다. 요청을 다시 보내고 싶을 때 이 값을 업데이트하여 useEffect를 실행시킵니다.
    • refetch는 데이터를 다시 불러오는 함수입니다. 이 함수를 호출하면 trigger를 업데이트하고 useEffect가 실행됩니다.
    • 위 코드에서 fetchData 함수는 async 키워드로 선언되어 있습니다. 이렇게 선언된 함수는 비동기 작업을 수행하는 함수입니다. 그리고 이 함수 내부에서 await 키워드를 사용하여 비동기 작업을 처리하고 있습니다. await 키워드는 axiosInstance(opts) 함수가 반환한 프라미스를 기다리는 역할을 합니다. 즉, axiosInstance(opts) 함수가 완료되고 응답이 올 때까지 대기하게 됩니다. 이후에는 응답 데이터를 변수 data에 할당하고 이를 사용하여 상태를 업데이트하게 됩니다. 비동기 작업이 성공하면 try 블록이 실행되어 상태를 업데이트하고, 실패하면 catch 블록이 실행되어 에러를 처리하게 됩니다. 이렇게 함으로써 비동기 작업을 보다 효율적으로 관리하고 에러를 처리할 수 있습니다.
  2. App 컴포넌트 설명:
    • useAxios 훅을 사용하여 데이터를 요청하고 결과를 받아옵니다.
    • 받아온 데이터의 상태를 확인하고, 데이터가 로딩 중인지, 오류가 발생했는지를 표시합니다.
    • Refetch 버튼을 클릭하면 refetch 함수가 호출되어 데이터를 다시 불러옵니다.
import React, { useEffect, useState } from "react";
import defaultAxios from "axios";
const useAxios = (opts, axiosInstance = defaultAxios) => {
  const [state, setState] = useState({
    loading: true,
    error: null,
    data: null
  });
  const [trigger, setTrigger] = useState(0); // trigger를 통해 useEffect를 실행시킨다.
  const refetch = () => {
    setState({
      ...state,
      loading: true
    });
    setTrigger(Date.now());
  }
  useEffect(() => {
    const fetchData = async () => {
      try {
        const { data } = await axiosInstance(opts);
        setState({
          ...state,
          loading: false,
          data
        });
      } catch (error) {
        setState({
          ...state,
          loading: false,
          error
        });
      }
    };
    if (opts.url) {
      fetchData();
    }
  }, [trigger]);
  return {...state, refetch};
};
export default function App() {
  const {loading,data,error, refetch} = useAxios({
    url: "https://yts.mx/api/v2/list_movies.json"
  });
  console.log(loading,data,error,refetch);
  return (
    <div className="App" style={{ height: "1000vh" }}>
      <h1>{data && data.status}</h1>
      <h2>{loading && "Loading"}</h2>
      <button onClick={refetch}>Refetch</button>
    </div>
  );
}
728x90