카테고리 없음

[React] 자동로그인 설정(redux-toolkit,tailwind사용)

maggieH 2025. 4. 4. 22:42

redux-toolkit을 활용한 자동로그인 설정하는 튜토리얼이다.

기본적인 구조는 생략하고 메인이 되는 페이지 구현 및 함수만 간략하게 정리해보았다.

1.로그인을 진행할 비동기함수를 설정하고, responsive값이 true일때 해당 유저 정보를 요청하여 initailState값에 넣는다.

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import api from "../../common/api";

export const adminLogin = createAsyncThunk("login/login", async (params) => {
  console.log(params)
  const res = await api.post("/admin/login", params);
  return res.data
});

const initialState = {
  state: null,
  adminNotauto: [],
};
const adminloginSlice = createSlice({
  name: "로그인",
  initialState,
  extraReducers: {
    [adminLogin.fulfilled]: (state, action) => {
      state.status = "success";
      state.adminNotauto = action.payload.admin;
    },
  },
});


export default adminloginSlice.reducer;

2.로그인을 진행할 페이지에 ui를 그려주고, 

input으로 userId,password를 onChange함수로 받는다.

자동로그인 input type checkbox의 경우 useRef로 잡고, 해당 checkbox의 current.checked값을 submit 할 부분의 조건식으로 활용하여 window 내장함수인 localStorage에 담는다.

import React, { useState, useRef, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useDispatch } from "react-redux";
import {
  adminLogin,
} from "../../../features/admin/adminloginSlice";
import { toast } from "react-toastify";
import toastCommonProps from "../../../common/Toast";

const SignIn = () => {
  const dispatch = useDispatch();
  const navigate = useNavigate();
  const [loginInput, setLoginInput] = useState({
    adminId: "",
    pass: "",
  });

  const checkRef = useRef()

  const onChangeLogin = (e) => {
    const { name, value } = e.target;
    setLoginInput({ ...loginInput, [name]: value });
  };

  const Loginin = async () => {
    const response = await dispatch(adminLogin(loginInput)).unwrap();
    try {
      if (response.ok === true) {
        if(checkRef.current.checked){
          window.localStorage.setItem("admin", JSON.stringify(response.admin));
        }else{
          window.localStorage.removeItem("admin")
        }
        toast(<p>로그인 성공</p>, toastCommonProps("top-right", "toast_alert"));
        navigate("/admin");
      } else {
        toast(<p>아이디와 비밀번호를 다시 확인해주세요.</p>, toastCommonProps("top-right", "toast_alert"));
      }
    } catch (error) {
      console.log(error);
    }
  };


  return (
    <div className="flex items-center">
      <div className="w-full max-w-lg bg-gray_100 rounded-[24px] shadow-md p-14">
        <div>
          <label htmlFor="adminId" className="text-caption_2 text-gray_10">
            아이디
          </label>
          <input
            id="adminId"
            type="text"
            name="adminId"
            value={loginInput.adminId}
            onChange={onChangeLogin}
            placeholder="아이디를 입력하세요"
            className="w-full p-[12px] border rounded-md focus:outline-none focus:ring-2 focus:ring-primary_100 mb-4 text-caption_2"
            onKeyPress={(e) => {
              if (e.key === "Enter") Loginin();
            }}
          />
          <label htmlFor="adminPass" className="text-caption_2 text-gray_10">
            비밀번호
          </label>
          <input
            id ="adminPass"
            type="password"
            value={loginInput.pass}
            onChange={onChangeLogin}
            autoComplete="one-time-code"
            name="pass"
            placeholder="비밀번호를 입력하세요"
            className="w-full p-[12px] border rounded-md focus:outline-none focus:ring-2 font-mono focus:ring-primary_100 text-caption_2"
            onKeyPress={(e) => {
              if (e.key === "Enter") Loginin();
            }}
          />
          <div className="pt-4 text-caption_2 text-gray_10 flex items-center gap-x-2">
            <input type="checkbox" id="check" ref={checkRef}/>
            <label htmlFor="check">자동로그인</label>
          </div>
          <button
            onClick={Loginin}
            className={
              "mt-4 w-full text-center border cursor-pointer rounded-md bg-primary_100 text-sm font-semibold py-4 text-gray_100"
            }
          >로그인
          </button>
        </div>
      </div>
    </div>
  );
};

export default SignIn;

3. user가 사용 페이지에 진입했을때 자동로그인 한경우, 일반로그인한 경우 user가 비거나 비지않았을 경우의 수를 삼항다항식에 담아, useEffect로 페이지 최초 출력시 혹은 새로고침시 페이지로 이동하도록 로직을 작성하였다.

import React, { useEffect,useState } from "react";
import { useNavigate } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";

const Admin = () => {
  const navigate = useNavigate();
  const dispatch = useDispatch();

  //notautouser:일반로그인 autouser:자동로그인
  const autouser = JSON.parse(window.localStorage.getItem("admin"));
  const notautouser = useSelector((state) => state.adminLogin.adminNotauto);
  const user = autouser === null && notautouser.length === 0 ?"nouser"
  :autouser !== null ? autouser : notautouser  ;
                         
  useEffect(() => {
    if(user !== "nouser"){
		//user가 자동로그인이거나, 자동로그인이 아닐때 출력
    }else{
      //페이지내에 user값이 없을때 페이지 signin으로 이동
      navigate("/admin/signin")
    }
  }, [dispatch,navigate]);
  [...]