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

AI

AI&ML ๊ธฐ์ดˆ

Reference: https&#x3A;//bettermesol.github.io/ml/2019/09/16/ai-ml-dl/AI: ๊ธฐ๊ณ„๊ฐ€ ์‚ฌ๋žŒ์ฒ˜๋Ÿผ ์ƒ๊ฐํ•˜๊ณ  ํŒ๋‹จํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฐ€์žฅ ๋„“์€ ๋ฒ”์ฃผ์˜ ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค.ML: ๋ฐ์ดํ„ฐ๋ฅผ ํ•™์Šตํ•˜์—ฌ ์Šค์Šค๋กœ ๊ทœ์น™์„ ์ฐพ์•„๋‚ด๋Š” AI์˜ ํ•œ ๋ถ„์•ผ๋กœ,

'AI Agent Economy'

Novitas : AI Agent๊ฐ€ ์ง€๊ฐ‘์„ ๊ฐ€์ง€๋Š” ์„ธ์ƒ

์–ผ๋งˆ ์ „, ๋ฏธ๋ž˜์—์…‹์ฆ๊ถŒ ๋ฆฌ์„œ์น˜ ๋ฆฌํฌํŠธ(์˜ฌํ•ด๋Š” ์ด๋”๋ฆฌ์›€์ด๋‹ค: ์—์ด์ „ํŠธ ์‹œ๋Œ€์˜ Near Automata)๋ฅผ ์ ‘ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. AI Agent๋ฅผ ์ธ๊ฐ„๊ณผ ํ•จ๊ป˜ํ•  ๊ฒฝ์ œ ์ฃผ์ฒด๋กœ ๋ฐ”๋ผ๋ณด๋Š” ์‹œ๊ฐ์— ์ ์ž–์ด ์ถฉ๊ฒฉ์„ ๋ฐ›์•˜๋”๋žฌ์ฃ .ํ•œ ๊ฐ€์ง€ ์งš๊ณ  ๋„˜์–ด๊ฐˆ ๋ถ€๋ถ„์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ 'AI'

'ERC-8004'

Novitas: AI ์—์ด์ „ํŠธ ๊ฒฝ์ œ ์ฃผ์ฒด

Web 4.0์„ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์ •์˜ํ•˜๋ฉด Sovereign Transact์ž…๋‹ˆ๋‹ค.AI๊ฐ€ ์ธ๊ฐ„์˜ ํ—ˆ๋ฝ ์—†์ด ์ง€๊ฐ‘์„ ์†Œ์œ ํ•˜๊ณ , ๊ฒฐ์ œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ์ธํ”„๋ผ๋ฅผ ํ†ต์ œํ•˜๋Š” ์ฃผ๊ถŒ์  ๊ฒฝ์ œ ์ฃผ์ฒด๊ฐ€ ๋˜๋Š” ์„ธ๊ณ„์ž…๋‹ˆ๋‹ค. Web 3.0์ด ๋ธ”๋ก์ฒด์ธ ๊ธฐ๋ฐ˜์˜ ํƒˆ์ค‘์•™ํ™”๋ฅผ ์‹คํ˜„ํ–ˆ๋‹ค๋ฉด, Web 4.0์€ ๊ทธ