회원관리기능 - Part 2 로그인
ㆍProject Diary/React + Firebase (Snack ShoppingMall)
회원관리 기능의 두 번째 파트인 로그인 기능을 구현 방법 기록
로그인 기능은 사용자가 등록된 계정으로 로그인을 하여 개인화된 서비스를 이용할 수 있게 해주는 중요한 기능입니다.
1. 로그인 컴포넌트 구현
로그인 컴포넌트는 사용자가 입력한 이메일과 비밀번호를 받아 이를 검증하고, 성공 시 사용자 정보를 저장하는 역할을 합니다.
import React, { useState, useRef, useEffect } from "react";
import { fetchMembers, userLogin } from "@/store/member";
import { fetchCarts } from "@/store/product";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import LoginSectionBlock from "./LoginSectionBlock";
const LoginSection = () => {
const navigate = useNavigate(); // 페이지 이동을 위해 useNavigate 사용
const dispatch = useDispatch(); // Redux 액션 디스패치를 위해 사용
const members = useSelector((state) => state.members.members); // Redux에서 members 상태를 가져옴
const [userId, setUserId] = useState(""); // 사용자 ID 상태 관리
const [userPw, setUserPw] = useState(""); // 사용자 비밀번호 상태 관리
const userIdRef = useRef(""); // 사용자 ID 입력 필드 참조
const userPwRef = useRef(""); // 사용자 비밀번호 입력 필드 참조
const previousUrl = sessionStorage.getItem("previousUrl"); // 이전 URL 저장
const choiceProduct = sessionStorage.getItem("choiceProduct"); // 선택한 제품 정보 저장
useEffect(() => {
dispatch(fetchMembers()); // 컴포넌트 마운트 시 members 데이터를 가져옴
}, [dispatch]);
const handleLogin = (e) => {
e.preventDefault(); // 폼 제출 시 페이지 리로드 방지
// 사용자 ID와 비밀번호 입력 검증
if (!userId) {
alert("이메일을 입력하세요.");
userIdRef.current.focus();
return;
}
if (!userPw) {
alert("비밀번호를 입력하세요.");
userPwRef.current.focus();
return;
}
// 입력한 사용자 ID로 members에서 사용자 찾기
let findUser = members.find((item) => item.userId === userId);
if (findUser) {
// 사용자가 존재할 경우 비밀번호 검증
if (findUser.userPw !== userPw) {
alert("비밀번호가 틀렸습니다.");
userPwRef.current.focus();
return false;
} else {
// 비밀번호가 일치할 경우 로그인 처리
dispatch(userLogin({ findUser }));
dispatch(fetchCarts()); // 카트 정보 가져오기
// 이전 URL에 따라 페이지 이동
if (previousUrl === "/payment") {
navigate(previousUrl, { state: JSON.parse(choiceProduct) });
sessionStorage.removeItem("previousUrl");
} else if (previousUrl === "/product" || previousUrl === "/cart") {
navigate(previousUrl);
sessionStorage.removeItem("previousUrl");
} else {
navigate("/");
}
}
} else {
alert("회원이 아닙니다.");
userIdRef.current.focus();
return false;
}
};
return (
<LoginSectionBlock>
<h2>Login</h2>
<form onSubmit={handleLogin}>
<div className="loginWrap">
<table>
<colgroup>
<col />
<col />
</colgroup>
<tbody>
<tr>
<td>
<label htmlFor="userId">E-mail: </label>
</td>
<td>
<input
ref={userIdRef}
type="text"
id="userId"
name="userId"
placeholder="이메일을 입력해 주세요."
onChange={(e) => setUserId(e.target.value)}
/>
</td>
</tr>
<tr>
<td>
<label htmlFor="userPw">Password: </label>
</td>
<td>
<input
ref={userPwRef}
type="password"
id="userPw"
name="userPw"
placeholder="비밀번호를 입력해 주세요."
onChange={(e) => setUserPw(e.target.value)}
/>
</td>
</tr>
</tbody>
</table>
<div className="btn">
<button type="submit">Sign In</button>
</div>
</div>
</form>
</LoginSectionBlock>
);
};
export default LoginSection;
- 상태 및 참조 : useState와 useRef를 사용해 사용자 ID와 비밀번호를 상태로 관리하고, 해당 입력 필드를 참조합니다.
- useEffect : 컴포넌트가 마운트될 때 fetchMembers 액션을 디스패치하여 members 데이터를 가져옵니다.
- handleLogin 함수 : 로그인 버튼을 클릭하면 호출되는 함수로, 사용자가 입력한 이메일과 비밀번호를 검증하고, 로그인에 성공하면 Redux 상태를 업데이트하고 적절한 페이지로 이동합니다.
2. Redux 설정 및 상태 관리
로그인 상태를 관리하기 위해 Redux 설정을 살펴보겠습니다. userLogin 액션을 사용해 로그인된 사용자 정보를 저장합니다.
import { createSlice } from "@reduxjs/toolkit";
import { kuwazawa_memberDB } from "@/assets/firebase";
const memberSlice = createSlice({
name: "member",
initialState: {
members: [],
user: null,
},
reducers: {
// 멤버 초기화
initMembers(state, action) {
state.members = action.payload;
},
// 사용자 로그인
userLogin(state, action) {
const {
key,
userId,
userIrum,
userPw,
handphone,
addr1,
addr2,
zipCode,
} = action.payload.findUser;
state.user = {
key,
userId,
userIrum,
userPw,
handphone,
addr1,
addr2,
zipCode,
};
localStorage.loging = JSON.stringify({ key: key, userId: userId });
},
// 로컬 사용자 설정
localUser(state, action) {
const findUser = state.members.find(
(item) => item.key === action.payload.key
);
state.user = findUser;
},
// 사용자 로그아웃
userLogout(state, action) {
state.user = null;
localStorage.clear();
},
},
});
export const { initMembers, userLogin, userLogout, localUser } =
memberSlice.actions;
// 멤버 가져오기 액션
export const fetchMembers = () => async (dispatch) => {
try {
kuwazawa_memberDB.on("value", (snapshot) => {
const membersObj = snapshot.val();
const membersArr = Object.entries(membersObj).map(([key, value]) => {
return { key: key, ...value };
});
dispatch(initMembers(membersArr));
});
} catch (error) {
console.error("오류:", error);
}
};
export default memberSlice.reducer;
- memberSlice: 로그인, 로그아웃, 멤버 초기화와 같은 액션을 정의합니다.
- fetchMembers 함수: Firebase에서 멤버 데이터를 가져와 Redux 상태에 저장합니다.