커스텀 훅은 React 에서 기본적으로 제공하는 기본적인 훅(useState, useEffect, useCallback, useMemo, useContext 등)과 비슷한 방식으로 작동하는 사용자 정의 hook 이다.

 

useState나 useEffect를 내장하여 기능을 확장하거나, 프로젝트 전체에서 반복적으로 사용되는 로직 등을 모듈화하여 여러 컴포넌트에서 재사용할 수 있도록 하는 것이 커스텀 훅의 목적이다. 

 

 

[커스텀 훅을 쓸 때의 장점 ]

 

-  반복적으로 사용되는 로직의 코드 반복을 줄이고, 재사용성을 높일 수 있다.

:예를 들어 동일한 데이터를 여러 컴포넌트에서 사용해야 하는 경우, 데이터를 불러오는 로직을 커스텀훅으로 분리하면 된다.

 

-  UI를 구성하는 부분과, 비즈니스 로직을 구성하는 부분이 분리되어 유지보수가 용이해지고 공동 작업에 유리해진다. 

: 데이터를 요청하거나 수정작업하는 부분을 별도의 custom hook 파일로 분리하면 코드 분량 자체가 간결해져서 유지보수가 편하고 여러 사람이 동일한 코드를 반복해서 작성할 필요가 없어진다. 

 

 

 

그리고 커스텀 훅을 작성하기 위해서는 몇가지 규칙이 있다. 

 

1. 훅의 이름은 반드시 use로 시작해야한다. 

const useMyHook = ()=>{

//커스텀 훅 안에서 useState,useEffect등을 사용하는 것도 가능하다! 

return ..

}

 

 

2. 반복문이나, 조건문 안에서 사용해서는 안된다. 

.
.
if(...){
useMyHook(); //조건에 위배됨
}

for(... of ..){
useMyHook() // 이것도 안 됨! error 발생  
}

올바른 방식으로 작성된 커스텀 훅은 리액트에서 useState 와 같이 리액트 훅으로 인식되기때문에 

반복문과 조건문 안에서 사용할 경우 에러가 발생한다. 

 

 

3. 커스텀 훅을 사용하는 각 컴포넌트는 독립적인 상태를 가진다. 커스텀 훅을 호출하는 컴포넌트마다 별도의 state가 생성되고, 그 state들은 서로 값을 공유하지 않는다. 

 

그 예시로 간단한 카운터 커스텀 훅을 작성해봤다. 

export const useMyCounter = () => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  const decrement = () => {
    setCount(count - 1);
  };

  
  return { count, increment, decrement };
};
/////////////////////////////////////////////////
const AComponent = () => {
  const { count, increment, decrement } = useMyCounter();

  return (
    <div>
      <span>값: {count}</span>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

const BComponent = () => {
  const { count } = useMyCounter();

  return (
    <div>
      <span>값: {count}</span>
    </div>
  );
};

 

이 카운터 훅을 A컴포넌트와 B컴포넌트에서 각각 사용하는 경우, 

A 컴포넌트에서 버튼을 통해 값을 증가하거나 감소시켜도 B컴포넌트의 counter state에는 영향을 미치지 않는다. 

 

 

 

 

커스텀 훅을 사용하면 좋은 예시의경우는 우선 아래 문서를 참고하면 좋다

(추후 카운터보다 더 좋은 예시를 첨부하겠음.. )

 

https://ko.react.dev/learn/reusing-logic-with-custom-hooks#extracting-your-own-custom-hook-from-a-component

 

커스텀 Hook으로 로직 재사용하기 – React

The library for web and native user interfaces

ko.react.dev

 

 

 

또는 React-query 등 라이브러리를 통해 서버 상태를 커스텀 훅으로 관리하는 방법도 있다.

 

리액트 쿼리는 자체 커스텀 훅을 제공하는 상태관리 라이브러리로 주로 대규모 프로젝트에서의 api통신과 비동기 데이터 처리를 편리하게 해주는 도구이다. 

 

useQueryClient 라는 훅을 통해 쿼리 객체를 선언하고, 

useQuery로 데이터 fetch 작업을, useMutation로 데이터의 수정과 삭제, 생성 작업을 수행한다. 

 

 

https://house-of-ham.tistory.com/entry/React-Query%EC%99%80-Axios%EB%A1%9C-%EB%B9%84%EC%A6%88%EB%8B%88%EC%8A%A4-%EB%A1%9C%EC%A7%81%EC%9D%84-%EC%B5%9C%EC%A0%81%ED%99%94-%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-feat-%EC%84%B1%EB%8A%A5%EC%B5%9C%EC%A0%81%ED%99%94-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B2%98%EB%A6%AC

 

React Query와 Axios로 비즈니스 로직을 최적화 하는 방법 (feat. 성능최적화, 데이터 처리)

백오피스 시스템을 개발하면서 복잡한 기능 구현과 데이터 처리가 큰 도전과제였다. 특히 대용량 데이터를 효율적으로 관리하고, 비즈니스 로직을 유연하게 확장하며, 일관된 방식으로 유지해

house-of-ham.tistory.com

자세한 사용법은 이 글을 참고하길! 

 

 

 

 

 

 

 

 

백오피스 시스템을 개발하면서 복잡한 기능 구현과 데이터 처리가 큰 도전과제였다.
특히 대용량 데이터를 효율적으로 관리하고, 비즈니스 로직을 유연하게 확장하며, 일관된 방식으로 유지해야 했다. 
 
이 과정에서 데이터 요청이 많고, 중복 요청을 유연하게 처리하기 위하여 React Query(Tanstack Query)를 사용하게 되었다. 
리액트 쿼리를 통해 데이터를 빠르게 가져오고, 캐시를 통해 중복 요청을 줄이면서 서비스를 최적화할 수 있었다. 
 
이번 글에서는 백오피스 시스템에서 복잡한 데이터 처리 기능을 효율적으로 관리하고, 성능을 최적화 했는지에 대해 공유하겠다! 
 
 

 


 
 
 
 
코드의 일관성과 유지보수성을 높이기 위해, 쿼리 키와 API 호출 로직을 별도로 분리했다. 이를 통해 팀원들과 코드 스타일을 맞추고, 유지보수가 쉬운 코드를 작성할 수 있었다.
또한 Axios를 적용하여 HTTP 요청을 간결하게 처리하고, 응답 데이터를 자동으로 JSON으로 파싱하여 쉽게 다루도록 했다. (Axios를 사용하면 JSON으로 응답이 돌아와서 추가 처리가 필요 없다!)
 
 
 
 
** 예시를 들기 위해 작성한 코드 입니다   ~.~  실제 업무용 코드 x 
 
쿼리 키 작성 

const employeeKey = {
  employee: ['employee'] as const,
  employeeWithID: (id: string) => ['employee', { id }] as const,
};

 
쿼리 키를 따로 파일로 분리하면 팀원들이 중복된 키를 작성하여 잘못된 데이터를 가져오거나 전송하는 문제를 방지할 수 있다. 유지보수 시에도 편리하므로 쿼리 키는 별도로 관리하는 것이 좋다.
 
 
 
커스텀 훅 작성 
 

import { useQuery } from 'react-query';
import axios from 'axios';
import { employeeKey } from "./employeeQueryKey";

// API 호출 함수 (전체 또는 개별 사원 정보 패칭)
const fetchEmployees = (id?: string) => 
  axios.get(`/api/employees${id ? `/${id}` : ''}`).then(res => res.data); //api 주소를 여기에 넣으면 됨

// useEmployeeInfo 커스텀 훅
const useEmployeeInfo = (employeeId?: string) => {
  const { data, isError, isLoading, error } = useQuery({
    queryKey: employeeId ? employeeKey.employeeWithID(employeeId) : employeeKey.employee,
    queryFn: () => fetchEmployees(employeeId), // employeeId가 없으면 undefined 전달
    staleTime: 1000 * 60 * 10, //캐시 지속 시간 
  });

  return {
    fetchData: data, // 패칭된 데이터
    isFetchDataLoading: isLoading, // 로딩 상태
    isFetchDataError: isError, // 에러 상태
    fetchError: error, // 에러 정보
  };
};

 
 
 
 
이제 컴포넌트에서 위에서 구현한 커스텀 훅을 통해 데이터를 가져오자 

const EmployeeInfo = ({ employeeId }: { employeeId: string }) => {
  // 사원 ID를 넘겨서 특정 사원의 정보를 패칭
  const { fetchData, isFetchDataLoading, isFetchDataError, fetchError } = useEmployeeInfo(employeeId);

  if (isFetchDataLoading) return <div>Loading employee data...</div>;
  if (isFetchDataError) return <div>Error loading data: {fetchError?.message}</div>;

  return (
    <div>
      <h1>Employee Name: {fetchData.name}</h1>
      <p>Position: {fetchData.position}</p>
      <p>Department: {fetchData.department}</p>
    </div>
  );
};

 
 
 
여기서 useQuery안에 들어가는 옵션 등을 props로 받아온다면 
더 높은 수준의 쿼리문을 작성할 수 있을 것이다 ~,~ 그 부분에 대해서는 추후 서술하겠음! 
 
 

마이크로프론트엔드란

 

각각의 독립적인 팀이 FE모듈을 개발하고, 이를 조합해서 하나의 사용자경험을 제공하는 방식. 

Webpack이 필수적임 ~.~ 

Webpack5 부터 포함되는 Module Federation 플러그인을 사용해서 리모트 모듈을 정의하고, 이를 호스트모듈에서 찾아 쓰도록 한다! 

 

장점

각 팀이 독립적으로 개발하고 배포할 수 있다 (각자의 깃 레포지토리에 업로드 하는 것이 가능함!)

이로인해 다른 모듈과의 의존성 충돌을 줄일 수 있다! 

각 팀이 선호하는 라이브러리나 프레임워크를 사용하는 것이 가능하다 (호스트에서는 리액트,리모트A에선 Angular,B에선 Vue를 사용하는것이 가능)

 

단점

중복  로드가 발생할 수 있음

 

라이브러리 중복-> 공유 라이브러리(module federation)도구를 사용하여 문제 해결 

네임 스페이스 중복->모듈 번들러(Webpack, Rollup)를 사용해 각 모듈을 독립적으로 번들링 or Web Component사용 or 자바스크림트 IIFE 즉시 호출 함수 표현식을 사용하여 전역변수의 범위를 제한. 

스타일 중복 -> CSS-IN-JS 라이브러리(styled등)를 사용

 

개발시에는 

리모트 모듈들이 모두 실행된 상태에서 호스트 모듈을 실행해야 정상적으로 작동하고 , 

 

실제 서버 배포시에는 

각각의 url에 리모트와 호스트가 모두 배포된 상태여야 정상적으로 동작한다. 

 

 

공부하면서 알게 된 내용을 조금씩 더 추가할 예정..

+ Recent posts