프로젝트 작업일지 : 로그인 (폼 만들기_React Hook Form)

작업에 들어가며

이전에 회원가입 컴포넌트를 만들어보았다.

 

그렇기에 로그인 컴포넌트를 만드는 일은 크게 어렵지 않게 진행될 것 같다.

 

이번에도 차크라UI를 사용하여 로그인 폼을 만들 것이며, 차크라 UI에 관한 사용법은 바로 아래 링크를 참조해놓겠다.

 

바로 시작해보자!

 

🙏 프로젝트 작업일지 : 회원가입 (폼 만들기_React Hook Form)


로그인 폼 구현

1. 이메일, 비밀번호 입력 필드 구현

import { Button, Input, Stack } from "@chakra-ui/react"
import { Field } from "../components/ui/field"
import { useForm } from "react-hook-form"
 
const AuthLogin = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm()
 
  const onSubmit = handleSubmit((data) => console.log(data))
 
  return (
    <form onSubmit={onSubmit}>
      <Stack gap="4" align="flex-start" maxW="sm">
        <Field
          label="이메일"
          invalid={!!errors.email}
          errorText={errors.email?.message}
        >
          <Input
            {...register("email", { required: "이메일은 필수 입력입니다.",
            pattern: {
                  value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
                  message: "올바른 이메일 형식으로 입력해주세요.",
                },
            })}
          />
        </Field>
        <Field
          label="비밀번호"
          invalid={!!errors.password}
          errorText={errors.password?.message}
        >
          <PasswordInput
            {...register("password", { required: "비밀번호는 필수 입력입니다." })}
          />
        </Field>
        <Button type="submit">로그인</Button>
      </Stack>
    </form>
  )
}
 
export default AuthLogin;

 

2. 이메일 기억하기, 아이디 / 비밀번호 찾기 구현

<Box>
	<Checkbox>이메일 기억하기</Checkbox>
	<Box>
		<FindEmail />
		<FindPassword />
	</Box>
</Box>

이메일 기억하기 체크박스와 아이디 / 비밀번호 찾기를 한 줄로 놓기 위해 <Box> 태그로 감싸주었다.

 

3. 로그인 핸들러 작성

const handleLogin = async (data) => {

    try {
      const response = await axios.post("http://localhost:8080/auth/login", data, {
        withCredentials: true,
      });

      if (response.status === 200) {
        alert("로그인 성공");
        navigate("/"); // 로그인 성공 후 메인 페이지로 이동
      }
    } catch (error) {
      alert("로그인 실패");
      if(error.response) {
        console.error('Response Error:', error.response.data); // 서버에서 반환한 에러 메시지
      } else {
        console.error('Axios Error:', error.message); // 네트워크 오류나 Axios 문제
      }   
    }
};
const onSubmit = handleSubmit((data) => {
	handleLogin(data);
});

회원가입 폼과 마찬가지로 React Hook Form은 자체적으로 폼 제출 핸들러인 handleSubmit 함수가 있기 때문에 submit시 작동되도록 해당 코드에 handleRegister 함수를 넣어주면 된다.

 

4. 완성

디테일한 디자인은 GPT의 도움을 받아 구현하였다.

import { Box, Button, Input, Stack, Link, Text, Image } from "@chakra-ui/react";
import { Field } from "../../components/ui/field";
import { PasswordInput } from "../../components/ui/password-input";
import { Checkbox } from "../../components/ui/checkbox";
import { KakaoLoginButton } from "./KakaoLogin";
import { useForm } from "react-hook-form";
import axios from "axios";
import FindPassword from "./FindPassword";
import FindEmail from "./FindEmail";
import { useNavigate } from "react-router-dom";

const AuthLogin = () => {
  const navigate = useNavigate();

  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm();

  const handleLogin = async (data) => {

    try {
      const response = await axios.post("http://localhost:8080/auth/login", data, {
        withCredentials: true,
      });

      if (response.status === 200) {
        alert("로그인 성공");
        setIsLoggedIn(true); // 로그인 상태 업데이트
        navigate("/");
      }
    } catch (error) {
      alert("로그인 실패");
      if(error.response) {
        console.error('Response Error:', error.response.data); // 서버에서 반환한 에러 메시지
      } else {
        console.error('Axios Error:', error.message); // 네트워크 오류나 Axios 문제
      }   
    }
  };

  const onSubmit = handleSubmit((data) => {
    handleLogin(data);
  });

  return (
    <form onSubmit={onSubmit}>
      <Box display="flex" alignItems="center" justifyContent="center" height="100vh">
        <Stack gap="4" align="flex-start" maxW="sm" width="full">
          <Link href="/">
            <Image
              src="https://example.com/logo.png"
              alt="로고"
              boxSize="45px"
              objectFit="contain"
              mb="4"
            />
          </Link>
          <Box display="flex" alignItems="center" justifyContent="space-between" width="full">
            <Text fontSize="2xl" fontWeight="bold">
              로그인
            </Text>
            <Link href="/register" color="orange.500" fontWeight="bold">
              회원가입
            </Link>
          </Box>
          <Field
            label="이메일"
            invalid={!!errors.email}
            errorText={errors.email?.message}
          >
            <Input
              size="lg"
              placeholder="이메일을 입력해주세요."
              {...register("email", {
                required: "이메일은 필수 입력입니다.",
                pattern: {
                  value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
                  message: "올바른 이메일 형식으로 입력해주세요.",
                },
              })}
            />
          </Field>
          <Field
            label="비밀번호"
            invalid={!!errors.password}
            errorText={errors.password?.message}
          >
            <PasswordInput
              size="lg"
              placeholder="비밀번호를 입력해주세요."
              {...register("password", {
                required: "비밀번호는 필수 입력입니다.",
              })}
            />
          </Field>

          <Box display="flex" alignItems="center" justifyContent="space-between" width="full">
            <Checkbox
              colorPalette="orange"
            >
              이메일 기억하기
            </Checkbox>

            <Box display="flex" alignItems="center" gap="1" mr="2">
              <FindEmail height="40px" />
              <FindPassword height="40px" />
            </Box>
          </Box>
          <Stack spacing="2" width="full" mt="1">
            <Button type="submit" colorPalette="orange" width="full" size="lg">
              로그인
            </Button>
          </Stack>
        </Stack>
      </Box>
    </form>
  );
};

export default AuthLogin;


작업을 마치며

✨ 나의 생각

이전에 회원가입 폼에 비해서는 확실히 무난하게 폼 구현이 진행되었다.

그러나 시큐리티와 이메일 / 비밀번호 찾기를 구현해봐야하는데,

구글링을 통해 많은 레퍼런스 자료들을 찾아봐야겠다.

시큐리티는 이전 프로젝트에서 사용한 코드에 학원에서 배운 코드들로 리팩토링하고, 


이메일 / 비밀번호 찾기는 모달로 띄워서 사용자 인증 정보를 입력 후 서버에 요청하여

모달창 내부에 아이디와 비밀번호를 띄우는 방법으로 진행해야 할 것 같다.

쉽지는 않겠지만 열심히 프로젝트를 진행해봐야겠다!

Reference

🙏 Chakra UI

🙏 Installation | Chakra UI

🙏 Components | Chakra UI