React 동적 UI - part4

wltjd1688·2025년 4월 21일

풀사이클

목록 보기
57/74

라우터 작성

  1. React Router를 사용
npm install react-router-dom @types/react-router-dom --save
  1. App.tsx에서 react-router-domcreateBrowserRouterRouterProvider를 사용해 라우트를 설정
const router = createBrowserRouter([
  {
    path: "/",
    element: <Layout><Home/></Layout>,
    errorElement: <Error/>
  },
  {
    path: "/books",
    element: <Layout><div>도서 목록</div></Layout>
  },
  {
    path: "/signup",
    element: <Layout><Signup/></Layout>
  }
  // 앞으로 /login, /reset, /cart, /orderList 등을 추가할 수 있습니다.
]);

function App() {
  return (
    <BookSotreThemeProvider>
      <ThemeSwitcher/>
      <RouterProvider router={router}/>
    </BookSotreThemeProvider>
  );
}

라우터 목록
1. 로그인: /login
2. 회원가입: /signup
3. 비밀번호 초기화: /reset
4. 도서목록: /books
5. 도서 상세: /books/{id}
6. 장바구니: /cart
7. 주문목록: /orderList

위와 같이 홈(/), 도서목록(/books) 등등의 라우터 목록을 생성하고,
에러 발생 시 보여줄 Error 컴포넌트도 지정할 수 있다.

모델 정의

이전에 만든 서버에서 응답형태를 보고 API통신때 사용할 수 있도록 응답형식에 맞게 미리 정리해야한다.
/models파일에 다음과 같이 파일을 만들어서 정리해었다.

// user.model.ts
export interface User {
  id: number;
  username: string;
  email: string;
  password?: string;
}

// book.model.ts
export interface Book {
  id: number;
  title: string;
  author: string;
  categoryId: number;
  price: number;
  description?: string;
}

// category.model.ts
export interface Category {
  id: number;
  name: string;
}

// cart.modal.ts
export interface CartItem {
  bookId: number;
  quantity: number;
}

// order.model.ts
export interface Order {
  id: number;
  userId: number;
  items: CartItem[];
  total: number;
  status?: string;
}

// pagenation.model.ts
export interface Page<T> {
  content: T[];
  page: number;
  size: number;
  totalElements: number;
  totalPages: number;
}

데이터 흐름


UI를 보여줄 view 컴포넌트로 부터 Hook이 API호출을 받으면, 이걸 백엔드 서버에 보낸다는 흐름이다.
이를 위해서 HTTP 클라이언트를 api/http.ts파일에 작성해주었다.

import axios, { AxiosRequestConfig } from 'axios';

const BASE_URL = "http://localhost:9999";
const DEFAULT_TIMEOUT = 30000;

export const createClient = (config?: AxiosRequestConfig) => {
  const instance = axios.create({
    baseURL: BASE_URL,
    timeout: DEFAULT_TIMEOUT,
    headers: { "content-type": "application/json" },
    withCredentials: true,
    ...config,
  });

  instance.interceptors.response.use(
    response => response,
    error => Promise.reject(error)
  );

  return instance;
};

export const httpClient = createClient();

이는 모든 httpClient를 통해 일정하게 호출하게 된다.

이후 API함수를 만들어 view 에서 사용할 수 있도록 만들어주었다.

React-hook-form

회원가입을 구현하기 위해서 React-hook-form을 사용하였다.

React hook form
React에서 폼 상태 관리를 간편하고성능 좋게 해주는 라이브러리이다.

  • 간편한 폼 관리: register, handleSubmit, errors 제공
  • 유효성 검사: required, pattern 등 옵션으로 간단 설정
  • 타입 안전성: 제네릭으로 폼 데이터 타입 지정 가능
    위 구조를 바탕으로, 라우팅에서부터 모델·API·UI까지 깔끔한 계층 구조를 갖춘 React 애플리케이션을 구현할 수 있습니다.
// src/pages/Signup.tsx
import React from "react";
import { useForm } from "react-hook-form";
import { signup } from "../api/auth.api";
import InputText from "../components/common/InputText";
import Button from "../components/common/Button";
import { useAlert } from "../hooks/useAlert";

export interface SignupProps {
  username: string;
  email: string;
  password: string;
}

const Signup: React.FC = () => {
  const { register, handleSubmit, formState: { errors } } = useForm<SignupProps>();
  const { showAlert } = useAlert();

  const onSubmit = async (data: SignupProps) => {
    try {
      await signup(data);
      showAlert("회원가입이 완료되었습니다.");
    } catch (err) {
      showAlert("회원가입에 실패했습니다.");
    }
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <InputText
        label="아이디"
        {...register("username", { required: "아이디는 필수 입력입니다." })}
        error={errors.username?.message}
      />
      <InputText
        type="email"
        label="이메일"
        {...register("email", { required: "이메일은 필수 입력입니다." })}
        error={errors.email?.message}
      />
      <InputText
        type="password"
        label="비밀번호"
        {...register("password", { required: "비밀번호는 필수 입력입니다." })}
        error={errors.password?.message}
      />
      <Button type="submit" size="large" scheme="primary">
        회원가입
      </Button>
    </form>
  );
};

export default Signup;
  • useForm<SignupProps>()로 폼 데이터 타입을 지정
  • handleSubmit(onSubmit)으로 유효성 검사 후 API 호출
  • useAlert로 나중에 window.alert말고 다른 라이브러리고 alert를 래핑하기 편하게 만듬
profile
일단 해!!!!

0개의 댓글