React 27장 - 로그인 구현하기 (2)
포스트
취소

React 27장 - 로그인 구현하기 (2)

React

자료구조

  • client
    • pages
      • Login.js
      • Mypage.js
    • src
      • App.js
      • index.js
  • server
    • controllers
      • users
        • login.js
        • logout.js
        • userInfo.js
      • index.js
    • db
      • data.js
    • index.js

서버 만들기

client/scr/App.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Login from "./pages/Login";
import Mypage from "./pages/Mypages";
import React, { useState, useEffect } from "react";
import axios from "axios";

axios.defaults.withCredentials = true;

function App() {
  const [isLogin, setIsLogin] = useState(false);
  const [userInfo, setUserInfo] = useState(null);

  const authHandler = () => {
    return axios
      .get("http://localhost:4000/userinfor")
      .then((res) => {
        setIsLogin(true);
        setUserInfo(res.data);
      })
      .cathc((err) => {
        return "...";
      });
  };

  useEffect(() => {
    authHandler();
  }, []);

  return (
    <BrowserRouter>
      <div className="main">
        <Routes>
          <Routes
            path="/"
            element={
              isLogin ? (
                <Mypage
                  userInfo={userInfo}
                  setIsLogin={setIsLogin}
                  setUserInfo={setUserInfo}
                />
              ) : (
                <Login setIsLogin={setIsLogin} setUserInfo={setUserInfo} />
              )
            }
          />
        </Routes>
      </div>
    </BrowserRouter>
  );
}

export default App;
  • axios.default.withCredentials = true
    • axios 라이브러리에서 설정하는 것 중 하나로, 이 옵션을 true로 설정하면 서버와의 요청 및 응답에서 쿠키와 같은 인증 정보를 사용할 수 있다.
    • 서버로 요청을 보낼 때 인증 정보를 포함하여 보내도록 기본 설정하는 것이며, 서버에서 요청을 인증하고 사용자의 인증 정보를 유지한다.
  • axios.get("http://localhost:4000/userinfo").the(...)
    • 서버에 정보를 요청하고 전달받은 정보를 userInfo 상태 값에 담는다.
    • 인증에 성공했다면 응답받은 데이터가 렌더링되도록 한다.
  • useEffect(()=>{authHandler},[])
    • 컴포넌트가 렌더링 될 때 함수를 실행시킨다.
    • 함수는 서버에게 데이터를 요청한다.
  • Mypage, Login 컴포넌트
    • set 을 내려 Login과 Mypage에서 입력받은 정보로 업데이트한다.

client/src/pages/Login.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import React, { useState } from "react";
import axios from "axios";

export default function Login({ setIsLogin, setUserInfo }) {
  const [loginInfo, setLoginInfo] = useState({
    userId: "",
    password: "",
  });

  const [checkedKeepLogin, setCheckedKeepLogin] = useState(false);
  const [errorMessage, setErrorMessage] = useState("");
  const handleInputValue = (key) => (e) => {
    setLoginInfo({ ...loginInfo, [key]: e.target.value });
  };
  const loginRequestHandler = () => {
    if (!loginInfo.userId || !loginInfo.password) {
      setErrorMessage("아이디와 비밀번호를 입력하세요.");
      return;
    }
    return axios
      .post("http://localhost:4000/login", { loginInfo, checkedKeepLogin })
      .then((res) => {
        setUserInfo(res.data);
        setIsLogin(true);
        setErrorMessage("");
      })
      .catch((err) => {
        setErrorMessage("로그인 할 수 없습니다.");
      });
  };

  return (
    <div className="container">
      <div className="left-box">
        <span>
          Education
          <p>for the</p>
          Real World
        </span>
      </div>
      <div className="right-box">
        <h1>AUTH STATES</h1>
        <form onSubmit={(e) => e.preventDefault()}>
          <div className="input-field">
            <span>ID</span>
            <input
              type="text"
              data-testid="id-input"
              onChange={handleInputValue("userId")}
            />
            <span>Password</span>
            <input
              type="password"
              data-testid="password-input"
              onChange={handleInputValue("password")}
            />
            <label className="checkbox-container">
              <input
                type="checkbox"
                onChange={() => setCheckedKeepLogin(!checkedKeepLogin)}
              />
              {"로그인 상태 유지하기"}
            </label>
          </div>
          <button type="submit" onClick={loginRequestHandler}>
            LOGIN
          </button>
          {errorMessage ? (
            <div id="alert-message" data-testid="alert-message">
              {errorMessage}
            </div>
          ) : (
            ""
          )}
        </form>
      </div>
    </div>
  );
}
  • Login({setIsLogin, setUserInfo})
    • App.js 로부터 상태 값을 내려받는다.
  • const [loginInfo, setLoginInfo] = useState({...})
    • 로그인 정보에 관한 상태 값을 갖고 있으며, 초기값은 빈 문자열로 둔다.
  • const [checkedKeepLogin, setCheckedKeepLogin] = useState(false)
    • 자동 로그인을 지정할 상태 값을 만든다.
  • consts [errorMessage, setErrorMessage] = useState("")
    • 로그인에 실패했을 때 출력할 메세지를 정한다.
  • const handleInputValue = (key) => (e) => {setLoginInfo({...loginInfo, [key]: e.target.value})}
    • input 아이디에서 작성한 값을 전달받아 상태 값의 id에 담는다.
    • input 패스워드도 같은 원리로 작동한다.
  • if(!loginInfo.userId || !loginInfo.password)
    • 아이디와 패스워드 input을 통해 상태 값이 변경될 건데, id와 password 중 하나라도 입력받지 않았다면 에레 메세지를 내보낸다.
  • axios.post("http://localhost:4000/login",{loginInfo, checkedKeepLogin})
    • 입력된 local 주소로 POST요청을 보내고, 요청 바디에는 우리가 작성한 아이디와 비밀번호가 담겨있는 loginInfo와 checkedKeepLogin 을 함께 보낸다.
  • then(res)=> {setUserInfo(res.data); setIsLogin(true); setErrorMessage("")}
    • 만약 요청이 성공했다면, 되돌아 온 응답의 데이터에는 user의 id가 담겨있다.
    • server 측에서 password는 삭제하고 보내진다.
    • Login에 대한 상태 값을 true로 바꾸고, 에러 메세지는 빈 문자열로 둔다.
    • setUserInfo, setIsLogin은 App.js로 보내진다.
  • catch((err)=> {setErrorMessage("...")})
    • 에러 발생 시 에러 메세지를 내보낸다.

client/src/pages/MyPage.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import React from "react";
import axios from "axios";

export default function Mypage({ userInfo, setIsLogin, setUserInfo }) {
  const logoutHandler = () => {
    return axios
      .post("http://localhost:4000/logout")
      .then((res) => {
        setIsLogin(false);
        setUserInfo(null);
      })
      .catch((err) => {
        return "...";
      });
  };

  return (
    <div className="container">
      <div className="left-box">
        <span>
          {`${userInfo.name}(${userInfo.userId})`}님,
          <p>반값습니다.</p>
        </span>
      </div>
      <div className="right-box">
        <h1>AUTH STATES</h1>
        <div className="input-field">
          <h3>내 정보</h3>
          <div className="userInfo-field">
            <div>{`${userInfo.position}`}</div>
            <div>{`${userInfo.email}`}</div>
            <div>{`${userInfo.location}`}</div>
            <article>
              <h3>Bio</h3>
              <span>{userInfo.bio}</span>
            </article>
          </div>
          <button className="logout-btn" onClick={logoutHandler}>
            LOGOUT
          </button>
        </div>
      </div>
    </div>
  );
}
  • axios.post("http://localhost:4000/logout").then(() => {...})
    • 로그아웃에서 데이터를 요청하여 데이터를 성공적으로 받아오면 Login값을 false로 바꿔 로그아웃시킨다.
    • UserInfo에 관한 정보도 모두 없앤다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.