[Week13] React(TypeScript) 기반의 동적 UI 개발(8) - 04/07

Kyulee·2026년 4월 7일

TIL 

목록 보기
64/90
post-thumbnail

지난 시간에 이어 프로젝트 중간 회고를 진행하고, 부족했던 기능들을 추가로 구현했습니다.


1. 프로젝트 중간 회고

회고를 하는 궁극적인 이유는 프로젝트를 더 잘 수행하기 위함입니다. 성장을 도모하고 문제를 해결하며, 유연성과 퍼포먼스를 향상시키는 데 목적이 있습니다.

지금까지 진행한 학습 주제는 타입과 데이터 모델 정의, 컴포넌트 작성, CSS 스타일링, 커스텀 훅 활용 등입니다. 여기에 생산성을 높이기 위해 스니펫을 사용하고, 데이터 모델 정의부터 리팩토링까지 이어지는 기능 단위의 작업 흐름을 정립하는 과정도 고민해 보았습니다. 일정한 틀을 두고 작업하면 다음 단계에 대한 고민을 줄이고 휴먼 에러를 방지할 수 있습니다.

이번 프로젝트의 KPT 회고를 정리해 보았습니다.

구분내용
Keep회원가입부터 주문까지의 흐름 경험, 생산성을 고려한 개발, 데이터 흐름에 맞춘 설계
Problem테마 스위처 미적용, 상대 경로 사용으로 인한 import 복잡도, 중복 코드, CSS 스타일링 미정리
Try 🚀테마 스위처 재배치, 절대 경로 적용, 중복 코드 제거, useAuth 훅 도입

2. 절대 경로 설정 (CRACO)

프로젝트 규모가 커지면 상대 경로를 사용할 때 경로 지정이 매우 복잡해집니다.

// 상대 경로 — 깊어질수록 복잡해집니다
import Button from '../../../components/common/Button';

// 절대 경로 — 어디서든 동일하게 사용할 수 있습니다
import Button from '@components/common/Button';

이를 해결하기 위해 절대 경로를 설정하는 것을 권장합니다. CRA 환경에서는 CRACO 라이브러리를 활용해 기존 webpack 설정을 덮어쓸 수 있습니다.

npm install @craco/craco craco-alias

craco.config.js 파일을 프로젝트 루트에 생성하고 설정을 추가한 뒤, package.json 의 스크립트를 변경해 적용합니다.

// package.json
"scripts": {
  "start": "craco start",
  "build": "craco build",
  "test": "craco test"
}

3. VSCode 커스텀 스니펫 만들기

VSCode에서 별도의 확장 프로그램을 설치하지 않고도 커스텀 스니펫을 만들어 사용할 수 있습니다. 자주 사용하는 코드 블록을 스니펫으로 등록해두면 반복적인 타이핑을 줄여 생산성을 높일 수 있습니다.

파일 > 기본 설정 > 사용자 코드 조각 에서 언어별로 스니펫을 추가할 수 있습니다.

// typescriptreact.json
{
  "React Functional Component": {
    "prefix": "rfc",
    "body": [
      "function ${1:ComponentName}() {",
      "  return (",
      "    <div>",
      "      $0",
      "    </div>",
      "  );",
      "}",
      "",
      "export default ${1:ComponentName};"
    ],
    "description": "React Functional Component"
  }
}

rfc 만 입력해도 컴포넌트 기본 구조가 자동 완성되기 때문에 작업 속도가 눈에 띄게 빨라집니다.


4. useAuth 커스텀 훅 적용

이전 구현에서는 로그인 관련 로직을 컴포넌트 내부에 직접 작성했습니다. 이를 분리해 useAuth 라는 커스텀 훅을 만들면 상태 관리가 훨씬 수월해집니다. 회원가입, 로그인, 비밀번호 초기화 요청 등의 로직을 한곳에 모아두고 필요한 컴포넌트에서 가져다 사용하도록 리팩토링을 진행했습니다.

// src/hooks/useAuth.ts
import { authLogin, authSignup, authResetPassword } from '../api/auth';

const useAuth = () => {
  const login = async (data: LoginForm) => {
    await authLogin(data);
  };

  const signup = async (data: SignUpForm) => {
    await authSignup(data);
  };

  const resetPassword = async (data: ResetPasswordForm) => {
    await authResetPassword(data);
  };

  return { login, signup, resetPassword };
};

export default useAuth;

컴포넌트에서는 아래처럼 간결하게 사용할 수 있습니다.

function LoginPage() {
  const { login } = useAuth();

  const onSubmit = async (data: LoginForm) => {
    await login(data);
  };

  // ...
}

비즈니스 로직이 컴포넌트 밖으로 빠져나오면 컴포넌트는 UI만 담당하게 되어 코드가 훨씬 읽기 쉬워집니다.


5. TanStack Query (React Query) 도입

과거 React Query 로 불렸던 TanStack Query 를 프로젝트에 도입했습니다. 이 라이브러리는 서버 상태를 가져오고, 캐싱하고, 동기화하며, 업데이트하는 비동기 작업을 쉽게 처리하도록 도와줍니다.

npm install @tanstack/react-query

useQuery 훅을 사용하면 데이터 패칭뿐만 아니라 로딩 상태도 직관적으로 처리할 수 있습니다.

import { useQuery } from '@tanstack/react-query';
import axiosInstance from '../api/axios';

const fetchBooks = async () => {
  const response = await axiosInstance.get('/books');
  return response.data;
};

function BookList() {
  const { data, isLoading } = useQuery({
    queryKey: ['books'],
    queryFn: fetchBooks,
  });

  if (isLoading) {
    return <div>로딩 중입니다.</div>;
  }

  return (
    <ul>
      {data.map((book) => (
        <li key={book.id}>{book.title}</li>
      ))}
    </ul>
  );
}

기존에는 useEffectuseState 를 조합해 데이터 패칭, 로딩 상태, 에러 처리를 각각 관리해야 했습니다. TanStack Query를 사용하면 이 모든 것을 isLoading, isError, data 하나로 깔끔하게 처리할 수 있습니다.

profile
안녕하세요 매일의 배움을 기록으로 자산화하는 개발자 이규현입니다 😊

0개의 댓글