프로젝트/[리스렌즈] 가전 제품 렌탈 리뷰 커뮤니티(LeaseLens)

[리스렌즈] 헤더, 로그인, 회원가입, 푸터 (TypeScript, axios, session) 구현

hyunh404 2024. 7. 9. 09:58
728x90

 

 

리스렌즈 프로젝트는 가전 구독 리뷰를 주제로 리액트, 타입스크립트를 활용한 프로젝트이다.

 

 

타입을 효율적으로 관리하고 컴파일 과정에서 타입 오류를 잡아 코드의 안정성을 높이기 위해 타입스크립트를 선택해서 프로젝트를 진행하게 되었다.

 

 

가장 먼저 구현한 컴포넌트와 페이지인 헤더, 로그인, 회원가입 페이지에 대해 설명하려 한다.

 

 

1. 헤더 컴포넌트

 

헤더 컴포넌트를 구현하면서 가장 신경을 많이 쓴 부분은 웹, 모바일 레이아웃 변경과 메뉴 토글이었다.

 

 

특히나 레이아웃은 잘못 구현한다면 사용자가 페이지를 이용함에 있어서 불편함을 느끼는 것으로 직결되기 때문에 반응형 레이아웃을 구성하고자 했다.

 

웹 환경에서는 한눈에 메뉴 이동 navigation을 확인할 수 있도록 nav bar 형태로 만들어주었고,

모바일 환경에서는 작은 화면에서 효율적으로 메뉴를 찾을 수 있도록 메뉴 아이콘을 이용해 토글을 구현해주었다.

 

 

메뉴 토글은 useState를 활용해 상태를 관리해주었고, 로그인 버튼은 axios 연결을 통해 상태에 따라 아이콘이 변화하도록 설정했다.

 

이어서 로그인 연결과 페이지 구현에 대해 이야기해볼까 한다.

 

 

웹 헤더
모바일 헤더

 


 

 

2. 로그인 구현

 

먼저 로그인 페이지 구현부터 시작해보겠다.

 

로그인 페이지는 기본 input 구조를 잡은 후 onChange 를 활용해 input 값을 관리해주었다.

 

 

특히 이 부분에서는 타입스크립트를 활용해 프로젝트를 진행하고 있었기에 타입을 지정해줘야 에러가 나지 않았다.

이벤트 타입을 지정하면서 사용해보지 못했던 타입들을 하나씩 배우게 되어 타입스크립트 활용히 더욱 의미있었다고 생각한다.

 

 

axios 요청으로 폼 데이터를 백엔드 서버로 보내기 위해 이벤트 타입을 아래와 같이 지정해 e.target의 value 값을 폼 데이터로 업데이트했다.

 

이어서 post요청으로 데이터를 보내 DB에 저장된 정보와 일치한다면 로그인 성공, 아니라면 로그인 실패 메세지가 뜨도록 설정해주었다.

또한 회원가입 페이지로 이동하거나 모달 창을 닫게 되면 폼이 초기화되도록 하는 상태 관리도 정의해 입력값이 남지 않도록 신경썼다.

 

post요청을 보내는 함수를 정의할 때에도 마찬가지로 폼 이벤트에 대한 타입을 지정해야했다.

 

  • React.ChangeEvent<HTMLInputElement> : ChangeEvent로서 입력 요소(예: <input>, <textarea>, <select>)의 값이 변경될 때 발생하는 이벤트를 나타냄. (제네릭 타입: <HTMLInputElement>는 이 이벤트가 발생하는 요소의 타입을 지정)
  • React.FormEvent :  <form> 요소에서 발생하는 이벤트를 나타냄. 주로 폼 제출(submit)과 관련된 이벤트를 처리할 때 사용
e: React.ChangeEvent<HTMLInputElement>
 
const handleLogin = async (e: React.FormEvent) => {
    e.preventDefault();
    try {
      const response = await axios.post(`${BACKHOST}/users/login`, {
        user_ID: formData.id,
        user_pw: formData.password
      });
      alert(response.data.message);
      window.location.replace(currentLocation);
      if (onClose) {
        onClose();
      }
      setFormData({
        name: '',
        id: '',
        password: '',
        confirmPassword: ''
      });
    } catch (error) {
      if (axios.isAxiosError(error)) {
        alert('로그인 실패: ' + error.response?.data.message);
        setFormData({
          name: '',
          id: '',
          password: '',
          confirmPassword: ''
        });
      } else {
        alert('로그인 실패: 알 수 없는 오류가 발생했습니다.');
        setFormData({
          name: '',
          id: '',
          password: '',
          confirmPassword: ''
        });
      }
    }
  };

 

 

728x90

 

 

3. 회원가입 구현

 

회원가입은 로그인 로직과 비슷하며, 한가지 추가한 점은

회원가입 시 비밀번호를 확인하는 것이었다.

 

useEffect를 사용해 onChange 이벤트로 폼 데이터가 변경될때마다 값을 비교해 사용자가 입력한 비밀번호와 비밀번호 확인 값이 같은지 확인하고,

다르다면 input 박스가 빨간색으로 표시되도록 css를 설정해주었다.

 

 useEffect(() => {
    if (formData.password && formData.confirmPassword) {
      setIsPasswordMatch(formData.password === formData.confirmPassword);
    }
  }, [formData.password, formData.confirmPassword]);
 style={{ border: isPasswordMatch ? '1px solid #005477' : '1px solid red' }}

 

 

로그인, 회원가입 모달 창

 


 

 

4. 로그인 session 헤더 연결

 

로그인과 헤더를 연결하는 과정은 백엔드에서 처리하는 세션을 통해 axios로 로그인 여부를 받아와서 화면이 적절하게 변경되어 구성되도록 코드를 작성했다.

 

 

useEffect를 활용해 컴포넌트가 렌더링될 때 로그인 여부를 비교하고 상태를 업데이트한다.

 

업데이트된 상태 변수를 활용해 로그인이 안되어 있다면 로그인 버튼을,

로그인이 된 상태라면 로그아웃과 기타 메뉴들이 보이도록 하는 버튼을 유동적으로 표시할 수 있게 되었다.

 

 useEffect(() => {
        const checkLoginStatus = async () => {
            try {
                const response = await axios.get(`${BACKHOST}/auth/check`);
                if (response.data.data.isAuthenticated) {
                    setIsLoggedIn(true);
                }
            } catch (error) {
                console.error('로그인 상태 확인 실패:', error);
            }
        };
        checkLoginStatus();
    }, [isLoggedIn]);
 
 
 {isLoggedIn ? (
         <img src={profile} alt="프로필 아이콘" className='head_profile' onClick={profileBtn} />
    ) : (
         <span onClick={handleLoginClick}>Login</span>
 )}

 

 

로그인 시 헤더

 

 


 

 

5. 푸터 컴포넌트 구현

 

푸터에는 기본적인 리스렌즈 정보를 작성해주었고,

일반적으로 회사의 sns, blog 등 홍보용 링크를 걸어두는 부분을 비워두는 것보다는 프로젝트를 조금 더 자세히 볼 수 있도록 하기 위해 프로젝트를 진행하면서 작성한 협업과 관련된 sns 링크를 걸어주었다.

 

협업 깃허브, 피그마, 노션 링크를 걸어두어 클릭 시 해당 링크로 이동할 수 있도록 했다.

반응형으로 레이아웃을 다르게 구성하여 모바일 화면에서도 사용자가 불편함 없이 정보를 확인할 수 있도록 scss를 작성했다.

 

푸터

 

 

728x90