LogIn ์ํ, ์ ์ญ์์ ๊ด๋ฆฌํ๊ธฐ(feat. Redux Toolkit) ๐
src/pages/LogInPage.js ๐ต
import React, { useState, useEffect } from "react";
import styled from "@emotion/styled";
import { loginUser } from "../modules/authSlice";
import { useNavigate } from "react-router-dom";
import ComponentWrapper from "../components/common/ComponentWrapper";
import { useDispatch } from "react-redux";
import { useSelector } from "react-redux";
const LogInTitle = styled.p`
text-align: center;
margin: 0px;
font-weight: bolder;
font-size: 40px;
`;
const LogInFormWrapper = styled.div`
/* display: flex;
flex-direction: column;
justify-content: center; */
/* min-width: 375px;
width: 100%;
height: 500px; */
/* margin: 0 auto; */
`;
const FormLabel = styled.p`
font-size: 16px;
margin-bottom: 8px;
`;
const FormInput = styled.input`
padding: 20px;
margin-bottom: 16px;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 16px;
width: 100%;
max-width: 600px;
`;
const SubmitButton = styled.button`
background-color: black;
color: #fff;
padding: 20px;
border: none;
border-radius: 8px;
font-size: 18px;
font-weight: bolder;
cursor: pointer;
width: 100%;
&:hover {
background-color: #fff;
color: black;
border: 2px solid black;
}
`;
const LogInPage = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const navigate = useNavigate();
const dispatch = useDispatch();
const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);
const goToSignUp = () => {
navigate("/signup");
};
const handleSignIn = (e) => {
e.preventDefault();
dispatch(loginUser({ email, password }));
};
useEffect(() => {
if (isAuthenticated) {
navigate("/");
}
}, [isAuthenticated]);
return (
<ComponentWrapper
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
{/* ๋ชจ๋ฐ์ผ 900px ์ดํ */}
<form onSubmit={handleSignIn}>
<LogInTitle>๋ก๊ทธ์ธ</LogInTitle>
<LogInFormWrapper>
<h2>์ด๋ฉ์ผ ๋ก๊ทธ์ธ</h2>
<FormLabel>Email</FormLabel>
<FormInput
type="email"
placeholder="์์ด๋(์ด๋ฉ์ผ ์ฃผ์)๋ฅผ ์
๋ ฅํ์ธ์"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<FormLabel>Password</FormLabel>
<FormInput
type="password"
placeholder="๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํ์ธ์"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<SubmitButton>๋ก๊ทธ์ธ</SubmitButton>
<div style={{ display: "flex", columnGap: "8px" }}>
<p style={{ fontWeight: "bolder" }}> ์ ์ก๊ฐ์ด ์ฒ์์ด์ ๊ฐ์?</p>
<p
style={{
color: "red",
fontWeight: "bolder",
cursor: "pointer",
}}
onClick={goToSignUp}
>
ํ์๊ฐ์
ํ๊ธฐ
</p>
</div>
</LogInFormWrapper>
</form>
</ComponentWrapper>
);
};
export default LogInPage;
src/modules/authSlice.js ๐ต
// authSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { auth } from "../firebase";
import { signInWithEmailAndPassword } from "firebase/auth";
// Firebase ์ธ์ฆ์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ๋ก๊ทธ์ธ ์ฒ๋ฆฌ
export const loginUser = createAsyncThunk(
"auth/loginUser",
async (credentials) => {
const { email, password } = credentials;
console.log(credentials);
try {
const userCredential = await signInWithEmailAndPassword(
auth,
email,
password
);
console.log(userCredential);
return userCredential.user.email;
} catch (error) {
console.log(error);
throw error;
}
}
);
const authSlice = createSlice({
name: "auth",
initialState: {
user: null,
isAuthenticated: false,
},
extraReducers: (builder) => {
builder.addCase(loginUser.fulfilled, (state, action) => {
console.log(action.payload);
state.user = action.payload;
console.log(state.user);
state.isAuthenticated = true;
});
},
});
export default authSlice.reducer;
ํด๊ฒฐ ๊ณผ์ ๐ข
์ด๋ค action์ ํํจ์ ์์ด, ํนํ ๊ฐ๋ฐ์๋ ๊ทธ๋ฅ... ๋ฐ์์ ๋๋ต์ ํด์๋ ์ ๋๋ค. ์ ์ญ ์ํ ๊ด๋ฆฌ์ ๋ํ ๊ทผ๊ฑฐ๋ถํฐ ์์ ํ๊ณ ์ ํ๋ค.
์ ์ญ ์ํ ๊ด๋ฆฌ๋, ์ํํธ์จ์ด ์ ํ๋ฆฌ์ผ์ด์
๋ด์์ ์ฌ๋ฌ ์ปดํฌ๋ํธ๋ ๋ชจ๋ ๊ฐ์ ๊ณต์ ๋๋ ๋ฐ์ดํฐ์ ์ํ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ๋ก ์ค ํ๋์ด๋ค. ๋ณต์กํ ๋ฐ์ดํฐ๋ฅผ ํ๋์ ํ์ผ์์ ๊ด๋ฆฌํจ์ผ๋ก์จ ์ฝ๋์ ์์ธก ๊ฐ๋ฅ์ฑ๊ณผ ๋๋ฒ๊น
์ ํจ์จ์ฑ, ์ฆ ์์ฐ์ฑ์ ์ ๊ณ ํ๋ ๋ฐ์ ๊ทธ ๋ณธ์ง์ด ์๋ค.

์ ์ฝ๋๋ ๋ก๊ทธ์ธ์ form ํ๊ทธ์ ์ฐ๋๋์ด ์๋ ํจ์์ด๋ค. ํต์ฌ์ dispatch์ด๋ค. form ํ๊ทธ ๋ด๋ถ์์ ์ ๊ณตํ๋ email๊ณผ password๋ฅผ reducer๋ก ์ ๋ฌํ๋ ์ ๋์, ์ต์ํ์ ์ญํ ๋ง์ ์ํํ๊ณ ์๋ค. ์ ์ญ ์ํ์ ๋ณธ์ง์ ๋ง๊ฒ ๋ฐ์ดํฐ์ ์ํ์ ๋ํ ๊ฐ๊ณต์ ํด๋น ํจ์์์ ์ด๋ฃจ์ด์ง์ง ์์ ๊ฒ์ด๋ค.

์ฌ์ฉ์ ๋ก๊ทธ์ธ์ ์ฒ๋ฆฌํ๋ ๋น๋๊ธฐ ํจ์๋ค. dispatch๋ฅผ ํตํด ์ ๋ฌํ email๊ณผ password๋ ์ ํจ์๊ฐ ๋ฐ์ ๊ฒ์ด๋ค.

์ฒ์์๋ ๊ตฌ๊ธ๋ง์ ํตํด auth.signInWith~~ ๋ฐฉ์์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ๋๋ฐ, ์ ์๋ฌ๊ฐ console์ ์ฐํ๋ค. firebase V9์์ ํจ์ ์ฌ์ฉ ๋ฐฉ์์ด ๋ฌ๋ผ์ก๊ธฐ์ ๋ฐ์ํ ์๋ฌ์๋ค. ์ ์ฝ๋์ฒ๋ผ auth๋ฅผ sign ํจ์ ๋ด๋ถ์ ๋ฃ์ด์ฃผ๋ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ๋ค.

๋ค์ ์๋ฌ๋ try ๋ฌธ ๋ด๋ถ์ return ๋ถ๋ถ์์ ๋ฐ์ํ๋ค. ์ง๋ ฌํ์ ๊ดํ ๋ด์ฉ์ ๋ค๋ฃจ๊ณ ์๋ค. ์ง๋ ฌํ ์์ฒด์ ๋ํด ๋ค๋ฃจ๋ฉด ์ฝ๋ฉ์ ์ฌ๊ธฐ์ ๋ฉ์ถ ๊ฒ ๊ฐ๋ค๊ณ ํ๋จํ๋ค. ๊ฐ๋จํ ์ ๋ฆฌํ๋ฉด, redux์ action์๋ ๋น์ง๋ ฌํ๋ ๊ฐ์ด ํฌํจ๋์ด ์์ผ๋ฉด ํด๋น ์๋ฌ๊ฐ ๋ฐ์ํ๋ค. firebase์ ์ฌ์ฉ์ ๊ฐ์ฒด๋ ๋ณต์กํ ๋ด๋ถ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ์ ์ง๋ ฌํํ๊ธฐ ์ด๋ ต๋ค๊ณ ํ๋ค. ๋ฐ๋ผ์ ํ์ฌ๋ก์๋ ์ฌ์ฉ์ ๊ฐ์ฒด๋ฅผ ํต์ผ๋ก returnํ๋ ๊ฒ์ด ์๋๋ผ ํ์ํ ์ ๋ณด๋ง ์ถ์ถํ๋ ๋ฐฉ์์ ํํ๊ณ , ์๋ฌ๋ ์ฌ๋ผ์ก๋ค.
๊ฒฐ๋ก ์ ์ผ๋ก fulfilled ๋์์ ๋ ์ด๊ธฐ๊ฐ user๋ ์ฌ์ฉ์์ email๋ก ์ ๋ฐ์ดํธ ๋๋ค.
๋ค์์ ์ค๋ ๋ง์ฃผํ ๋ง์ง๋ง ์๋ฌ๋ค.

ํ์ด์ง ์ด๋์ ๋ํ ๋ก์ง์ useEffect ํจ์ ์ธ๋ถ์์ ์์ฑํ ํ์ ๋ฐ์ํ ์๋ฌ์๋ค.

isAuthentication์ ํตํด useEffect ๋ด๋ถ์์ ํ์ด์ง ์ด๋์ ์ฒ๋ฆฌํ๋ค. ์ฆ, ๋ก๊ทธ์ธ์ ์ฑ๊ณตํ๋ฉด home์ผ๋ก ์ด๋ํ๋ค. ๊ทธ๋ฐ๋ฐ ์ด๋์ด ์ ๋๋ค.

์์กด์ฑ ๋ฐฐ์ด์ ํน์ value๋ฅผ ์ ๋ ฅํด์ผ ํ๋ค. value๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ํธ์ถ๋๋ฉฐ, ์ด๋ value๋ ๋ ๋๋ง๊ณผ ๊ด๋ จ๋ ๊ฐ์ด์ด์ผ ํ๋ค.

ํ... ๋ํ๋ฏผ๊ตญ ๋ง์ธ