React
자료구조
- client
- …
- pages
- Login.js
- Mypage.js
- src
- App.js
- index.js
- server
- controllers
- users
- login.js
- logout.js
- userInfo.js
- index.js
- users
- db
- data.js
- index.js
- controllers
서버 만들기
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에 관한 정보도 모두 없앤다.