React

[TIL/React] 2023/08/15 ๐Ÿ‡ฐ๐Ÿ‡ท

LogIn ์ƒํƒœ, ์ „์—ญ์—์„œ ๊ด€๋ฆฌํ•˜๊ธฐ(feat. Redux Toolkit) ๐ŸŸ  > src/pages/LogInPage.js ๐Ÿ”ต > src/modules/authSlice.js ๐Ÿ”ต > ํ•ด๊ฒฐ ๊ณผ์ • ๐ŸŸข ๊ฐœ์š” ์–ด๋–ค action์„ ํ–‰ํ•จ์— ์žˆ์–ด, ํŠนํžˆ ๊ฐœ๋ฐœ์ž๋Š” ๋”ฐ์œ„์˜ ๋Œ€๋‹ต์„ ํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค. ์— ๋Œ€ํ•œ ๊ทผ๊ฑฐ๋ถ€ํ„ฐ ์„œ์ˆ ํ•˜๊ณ ์ž ํ•œ๋‹ค. ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ๋Š”, ์†Œ...

2023๋…„ 8์›” 15์ผ3min read

LogIn ์ƒํƒœ, ์ „์—ญ์—์„œ ๊ด€๋ฆฌํ•˜๊ธฐ(feat. Redux Toolkit) ๐ŸŸ 

src/pages/LogInPage.js ๐Ÿ”ต

code
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 ๐Ÿ”ต

code
// 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์„ ํ–‰ํ•จ์— ์žˆ์–ด, ํŠนํžˆ ๊ฐœ๋ฐœ์ž๋Š” ``๊ทธ๋ƒฅ...` ๋”ฐ์œ„์˜ ๋Œ€๋‹ต์„ ํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค. `์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ``์— ๋Œ€ํ•œ ๊ทผ๊ฑฐ๋ถ€ํ„ฐ ์„œ์ˆ ํ•˜๊ณ ์ž ํ•œ๋‹ค.

์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ๋Š”, ์†Œํ”„ํŠธ์›จ์–ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋‚˜ ๋ชจ๋“ˆ ๊ฐ„์— ๊ณต์œ ๋˜๋Š” ๋ฐ์ดํ„ฐ์™€ ์ƒํƒœ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•๋ก  ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜์˜ ํŒŒ์ผ์—์„œ ๊ด€๋ฆฌํ•จ์œผ๋กœ์จ ์ฝ”๋“œ์˜ ์˜ˆ์ธก ๊ฐ€๋Šฅ์„ฑ๊ณผ ๋””๋ฒ„๊น…์˜ ํšจ์œจ์„ฑ, ์ฆ‰ ``์ƒ์‚ฐ์„ฑ์„ ์ œ๊ณ ``ํ•˜๋Š” ๋ฐ์— ๊ทธ ๋ณธ์งˆ์ด ์žˆ๋‹ค.

2. ์ฝ”๋“œ ์ˆ˜์ • ๋ฐ ์—๋Ÿฌ

์œ„ ์ฝ”๋“œ๋Š” ๋กœ๊ทธ์ธ์˜ 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๋Š” ๋ Œ๋”๋ง๊ณผ ๊ด€๋ จ๋œ ๊ฐ’์ด์–ด์•ผ ํ•œ๋‹ค.

ํ›„... ๋Œ€ํ•œ๋ฏผ๊ตญ ๋งŒ์„ธ

More to read

Amazon VPC

Amazon VPC Architecture ์ดํ•ดํ•˜๊ธฐ

์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ๊ธฐํšํ•˜๋ฉฐ, ๊ฐœ๋ฐœ์—์„œ ๋ฌด์—‡์„ ๊ฐ€์žฅ ๋จผ์ € ๊ณ ๋ฏผํ•ด์•ผ ํ•˜๋Š”์ง€ ๋‹ค์‹œ ๋Œ์•„๋ณด๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.ํ•œ๋•Œ๋Š” ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ๋ชจ๋“  ์„ค๊ณ„์˜ ์ถœ๋ฐœ์ ์ด๋ผ๊ณ  ๋ฏฟ์—ˆ์Šต๋‹ˆ๋‹ค. ์œ ์ €๊ฐ€ ๋ฌด์—‡์„ ๋ณด๊ณ , ์–ด๋–ค ํ๋ฆ„์—์„œ ๋จธ๋ฌด๋ฅด๊ณ  ์ดํƒˆํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ดํ•ด ์—†์ด ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ ๋‹ค๋Š” ๊ฑด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๊ธฐ

'์›์‚ฌ์ดํŠธ'

ํ”„๋ก ํŠธ์—”๋“œ ๊ด€์ ์œผ๋กœ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ดํ•ดํ•˜๊ธฐ

์˜ค๋žœ๋งŒ์— ๋ฐฉ๋ฒ•๋ก ์— ๊ด€ํ•œ ๊ธ€์„ ์“ฐ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ตœ๊ทผ ์ƒํ™ฉ์€ ์ด๋ ‡์Šต๋‹ˆ๋‹ค. SSAFY์—์„œ๋Š” ํ•˜๋ฃจ์— ์—„์ฒญ๋‚œ ์–‘์˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฌธ์ œ๋“ค์„ ๊ณผ์ œ๋กœ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ ๊ณผ์ •์—์„œ, '๊ตฌํ˜„๋ ฅ'์ด ๋งค์šฐ ๋–จ์–ด์ง„๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์™„์ „ํžˆ ์–ด๋ ค์šด ๋ฌธ์ œ๋ผ๋ฉด '์•„์‰ฌ์›€'์ด๋ผ๋Š” ๊ฐ์ •์กฐ์ฐจ ๋А๋ผ์ง€

Subnet

VPC ์„ค๊ณ„์˜ ์‹œ์ž‘: IP์™€ Subnet

๋ฐ˜๋ณต๋˜๋Š” ๋ฃจํ‹ด ์†์—์„œ ์–ป์€ ์•ˆ์ •๊ฐ์„ ๋ฐœํŒ ์‚ผ์•„, ์ด์ œ๋Š” ๊ธฐ์ˆ ์  ์ŠคํŽ™ํŠธ๋Ÿผ์„ ๋„“ํžˆ๊ธฐ ์œ„ํ•œ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ์— ์ฐฉ์ˆ˜ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์˜ ๋ชฉํ‘œ๋Š” ๋‹จ์ˆœํ•œ ํฌํŠธํด๋ฆฌ์˜ค ๊ตฌ์ถ•์„ ๋„˜์–ด, ์‹ค์ œ ์„œ๋น„์Šค ์ˆ˜์ค€์˜ ๋ธ”๋กœ๊ทธ ์‹œ์Šคํ…œ ๊ตฌํ˜„๊ณผ ๋‹ค๊ตญ์–ด ์ฒ˜๋ฆฌ ์ ์šฉ ๋“ฑ ์‹ค๋ฌด์— ๊ฐ€๊นŒ์šด ์—ญ๋Ÿ‰์„ ํ•œ ๋‹จ๊ณ„