[TIL/React] 2023/08/15 πŸ‡°πŸ‡·

원민관·2023λ…„ 8μ›” 15일
0

[TIL]

λͺ©λ‘ 보기
98/159
post-thumbnail

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;

ν•΄κ²° κ³Όμ • 🟒

  1. κ°œμš”

μ–΄λ–€ action을 행함에 μžˆμ–΄, 특히 κ°œλ°œμžλŠ” κ·Έλƒ₯... λ”°μœ„μ˜ λŒ€λ‹΅μ„ ν•΄μ„œλŠ” μ•ˆ λœλ‹€. μ „μ—­ μƒνƒœ 관리에 λŒ€ν•œ κ·Όκ±°λΆ€ν„° μ„œμˆ ν•˜κ³ μž ν•œλ‹€.

μ „μ—­ μƒνƒœ κ΄€λ¦¬λŠ”, μ†Œν”„νŠΈμ›¨μ–΄ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ‚΄μ—μ„œ μ—¬λŸ¬ μ»΄ν¬λ„ŒνŠΈλ‚˜ λͺ¨λ“ˆ 간에 κ³΅μœ λ˜λŠ” 데이터와 μƒνƒœλ₯Ό 효율적으둜 κ΄€λ¦¬ν•˜λŠ” 방법둠 쀑 ν•˜λ‚˜μ΄λ‹€. λ³΅μž‘ν•œ 데이터λ₯Ό ν•˜λ‚˜μ˜ νŒŒμΌμ—μ„œ κ΄€λ¦¬ν•¨μœΌλ‘œμ¨ μ½”λ“œμ˜ 예츑 κ°€λŠ₯μ„±κ³Ό λ””λ²„κΉ…μ˜ νš¨μœ¨μ„±, 즉 생산성을 μ œκ³ ν•˜λŠ” 데에 κ·Έ 본질이 μžˆλ‹€.

  1. μ½”λ“œ μˆ˜μ • 및 μ—λŸ¬

μœ„ μ½”λ“œλŠ” 둜그인의 form νƒœκ·Έμ— μ—°λ™λ˜μ–΄ μžˆλŠ” ν•¨μˆ˜μ΄λ‹€. 핡심은 dispatch이닀. form νƒœκ·Έ λ‚΄λΆ€μ—μ„œ μ œκ³΅ν•˜λŠ” emailκ³Ό passwordλ₯Ό reducer둜 μ „λ‹¬ν•˜λŠ” μ •λ„μ˜, μ΅œμ†Œν•œμ˜ μ—­ν• λ§Œμ„ μˆ˜ν–‰ν•˜κ³  μžˆλ‹€. μ „μ—­ μƒνƒœμ˜ λ³Έμ§ˆμ— 맞게 데이터와 μƒνƒœμ— λŒ€ν•œ 가곡은 ν•΄λ‹Ή ν•¨μˆ˜μ—μ„œ 이루어지지 μ•Šμ„ 것이닀.

μ‚¬μš©μž λ‘œκ·ΈμΈμ„ μ²˜λ¦¬ν•˜λŠ” 비동기 ν•¨μˆ˜λ‹€. dispatchλ₯Ό 톡해 μ „λ‹¬ν•œ emailκ³Ό passwordλŠ” μœ„ ν•¨μˆ˜κ°€ 받을 것이닀.

μ²˜μŒμ—λŠ” ꡬ글링을 톡해 auth.signInWith~~ λ°©μ‹μœΌλ‘œ μ½”λ“œλ₯Ό μž‘μ„±ν–ˆλŠ”λ°, μœ„ μ—λŸ¬κ°€ console에 μ°ν˜”λ‹€. firebase V9μ—μ„œ ν•¨μˆ˜ μ‚¬μš© 방식이 λ‹¬λΌμ‘ŒκΈ°μ— λ°œμƒν•œ μ—λŸ¬μ˜€λ‹€. μœ„ μ½”λ“œμ²˜λŸΌ authλ₯Ό sign ν•¨μˆ˜ 내뢀에 λ„£μ–΄μ£ΌλŠ” λ°©μ‹μœΌλ‘œ ν•΄κ²°ν–ˆλ‹€.

reference: https://velog.io/@seondal/Firebase-v9λΆ€ν„°-달라진-인증λͺ¨λ“ˆ-μ‚¬μš©λ²•#2-auth-κ΄€λ ¨-ν•¨μˆ˜λ“€-μ‚¬μš©

λ‹€μŒ μ—λŸ¬λŠ” try λ¬Έ λ‚΄λΆ€μ˜ return λΆ€λΆ„μ—μ„œ λ°œμƒν–ˆλ‹€. 직렬화에 κ΄€ν•œ λ‚΄μš©μ„ 닀루고 μžˆλ‹€. 직렬화 μžμ²΄μ— λŒ€ν•΄ 닀루면 코딩을 μ—¬κΈ°μ„œ 멈좜 것 κ°™λ‹€κ³  νŒλ‹¨ν–ˆλ‹€. κ°„λ‹¨νžˆ μ •λ¦¬ν•˜λ©΄, redux의 actionμ—λŠ” λΉ„μ§λ ¬ν™”λœ 값이 ν¬ν•¨λ˜μ–΄ 있으면 ν•΄λ‹Ή μ—λŸ¬κ°€ λ°œμƒν•œλ‹€. firebase의 μ‚¬μš©μž κ°μ²΄λŠ” λ³΅μž‘ν•œ λ‚΄λΆ€ ꡬ쑰λ₯Ό 가지고 μžˆκΈ°μ— μ§λ ¬ν™”ν•˜κΈ° μ–΄λ ΅λ‹€κ³  ν•œλ‹€. λ”°λΌμ„œ ν˜„μž¬λ‘œμ„œλŠ” μ‚¬μš©μž 객체λ₯Ό ν†΅μœΌλ‘œ returnν•˜λŠ” 것이 μ•„λ‹ˆλΌ ν•„μš”ν•œ μ •λ³΄λ§Œ μΆ”μΆœν•˜λŠ” 방식을 νƒν–ˆκ³ , μ—λŸ¬λŠ” μ‚¬λΌμ‘Œλ‹€.

결둠적으둜 fulfilled λ˜μ—ˆμ„ λ•Œ μ΄ˆκΈ°κ°’ userλŠ” μ‚¬μš©μžμ˜ email둜 μ—…λ°μ΄νŠΈ λœλ‹€.

λ‹€μŒμ€ 였늘 λ§ˆμ£Όν•œ λ§ˆμ§€λ§‰ μ—λŸ¬λ‹€.

νŽ˜μ΄μ§€ 이동에 λŒ€ν•œ λ‘œμ§μ„ useEffect ν•¨μˆ˜ μ™ΈλΆ€μ—μ„œ μž‘μ„±ν•œ 탓에 λ°œμƒν•œ μ—λŸ¬μ˜€λ‹€.

isAuthentication을 톡해 useEffect λ‚΄λΆ€μ—μ„œ νŽ˜μ΄μ§€ 이동을 μ²˜λ¦¬ν–ˆλ‹€. 즉, λ‘œκ·ΈμΈμ— μ„±κ³΅ν•˜λ©΄ home으둜 μ΄λ™ν•œλ‹€. 그런데 이동이 μ•ˆ 됐닀.

μ˜μ‘΄μ„± 배열에 νŠΉμ • valueλ₯Ό μž…λ ₯ν•΄μ•Ό ν•œλ‹€. valueκ°€ 변경될 λ•Œλ§ˆλ‹€ 호좜되며, μ΄λ•Œ valueλŠ” λ Œλ”λ§κ³Ό κ΄€λ ¨λœ 값이어야 ν•œλ‹€.

ν›„... λŒ€ν•œλ―Όκ΅­ λ§Œμ„Έ

profile
Write a little every day, without hope, without despair ✍️

0개의 λŒ“κΈ€