React + TypeScript

React + TypeScript로 회원가입 및 로그인 화면 만들기

지오준 2025. 2. 25. 10:00
반응형

1. 개요

웹 애플리케이션에서 회원가입 및 로그인 기능은 필수적인 요소입니다. 이번 글에서는 React + TypeScript + Tailwind CSS를 사용하여 간단한 회원가입 및 로그인 화면을 구현해 보겠습니다.

2. 프로젝트 설정

먼저 React 프로젝트를 생성하고 필요한 패키지를 설치합니다.

npx create-react-app auth-app --template typescript
cd auth-app
npm install react-router-dom tailwindcss @heroicons/react axios

그 후 Tailwind CSS를 설정합니다.

npx tailwindcss init -p

tailwind.config.js를 열고 아래처럼 수정합니다.

/** @type {import('tailwindcss').Config} */
export default {
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

index.css에 Tailwind 기본 스타일을 추가합니다.

@tailwind base;
@tailwind components;
@tailwind utilities;

3. 라우팅 설정

회원가입과 로그인 페이지를 라우팅하기 위해 react-router-dom을 설정합니다.

App.tsx 수정

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Login from "./pages/Login";
import Signup from "./pages/Signup";

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/login" element={<Login />} />
        <Route path="/signup" element={<Signup />} />
      </Routes>
    </Router>
  );
}

export default App;

4. 로그인 화면 구현 (Login.tsx)

import { useState } from "react";
import { useNavigate } from "react-router-dom";

const Login = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const navigate = useNavigate();

  const handleLogin = (e: React.FormEvent) => {
    e.preventDefault();
    console.log("로그인 요청:", { email, password });
    // 실제 로그인 API 연동 필요
    navigate("/dashboard");
  };

  return (
    <div className="flex h-screen items-center justify-center bg-gray-100">
      <div className="w-full max-w-md bg-white p-6 rounded-lg shadow-md">
        <h2 className="text-2xl font-semibold text-center">로그인</h2>
        <form onSubmit={handleLogin} className="mt-4">
          <div>
            <label className="block text-gray-700">이메일</label>
            <input
              type="email"
              className="w-full p-2 border border-gray-300 rounded mt-1"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              required
            />
          </div>
          <div className="mt-4">
            <label className="block text-gray-700">비밀번호</label>
            <input
              type="password"
              className="w-full p-2 border border-gray-300 rounded mt-1"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              required
            />
          </div>
          <button
            type="submit"
            className="w-full mt-6 bg-blue-500 text-white py-2 rounded hover:bg-blue-600"
          >
            로그인
          </button>
        </form>
        <p className="mt-4 text-center text-sm">
          계정이 없으신가요?{" "}
          <button
            onClick={() => navigate("/signup")}
            className="text-blue-500 hover:underline"
          >
            회원가입
          </button>
        </p>
      </div>
    </div>
  );
};

export default Login;

5. 회원가입 화면 구현 (Signup.tsx)

import { useState } from "react";
import { useNavigate } from "react-router-dom";

const Signup = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const navigate = useNavigate();

  const handleSignup = (e: React.FormEvent) => {
    e.preventDefault();
    if (password !== confirmPassword) {
      alert("비밀번호가 일치하지 않습니다.");
      return;
    }
    console.log("회원가입 요청:", { email, password });
    // 실제 회원가입 API 연동 필요
    navigate("/login");
  };

  return (
    <div className="flex h-screen items-center justify-center bg-gray-100">
      <div className="w-full max-w-md bg-white p-6 rounded-lg shadow-md">
        <h2 className="text-2xl font-semibold text-center">회원가입</h2>
        <form onSubmit={handleSignup} className="mt-4">
          <div>
            <label className="block text-gray-700">이메일</label>
            <input
              type="email"
              className="w-full p-2 border border-gray-300 rounded mt-1"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              required
            />
          </div>
          <div className="mt-4">
            <label className="block text-gray-700">비밀번호</label>
            <input
              type="password"
              className="w-full p-2 border border-gray-300 rounded mt-1"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              required
            />
          </div>
          <div className="mt-4">
            <label className="block text-gray-700">비밀번호 확인</label>
            <input
              type="password"
              className="w-full p-2 border border-gray-300 rounded mt-1"
              value={confirmPassword}
              onChange={(e) => setConfirmPassword(e.target.value)}
              required
            />
          </div>
          <button
            type="submit"
            className="w-full mt-6 bg-green-500 text-white py-2 rounded hover:bg-green-600"
          >
            회원가입
          </button>
        </form>
        <p className="mt-4 text-center text-sm">
          이미 계정이 있으신가요?{" "}
          <button
            onClick={() => navigate("/login")}
            className="text-blue-500 hover:underline"
          >
            로그인
          </button>
        </p>
      </div>
    </div>
  );
};

export default Signup;

6. 마무리

이제 npm start를 실행하면 로그인 및 회원가입 페이지를 확인할 수 있습니다.
다음 단계로 백엔드 API 연동을 추가하면 실제 사용자 데이터를 저장하고 인증 기능을 확장할 수 있습니다.

이와 같은 방식으로 React + TypeScript 환경에서 UI를 구성하고 로직을 관리하는 방법을 익히면 더욱 확장성 있는 프로젝트를 만들 수 있습니다. 🚀

반응형