백엔드 노드 서버 구축하기
버전이 다르기 때문에 소스가 강좌와 다를 수 있다.
버전
next: 13.0.4
antd: 5.0.1
소스 : https://github.dev/braverokmc79/node-bird-sns
46. 회원가입 구현하기
강의 :
백엔드
app.js
~
const express = require('express');
const postRouter = require('./routes/posts');
const userRouter = require('./routes/user');
const db = require('./models');
const app = express();
db.sequelize.sync()
.then(() => {
console.log('db 연결 성공');
})
.catch(console.error);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
~
app.use('/post', postRouter);
app.use('/user', userRouter);
비밀번호 암호화 위해
$ npm i bcrypt
routes/user.js
const express = require('express');
const { User } = require('../models');
const bcrypt = require('bcrypt');
const router = express.Router();
router.get('/', (req, res) => {
// User.create
console.log(" get 백엔드 : ", req.body);
res.json({ success: true })
});
router.post('/', async (req, res, next) => {
try {
console.log(" 백엔드 : ", req.body);
const exUser = await User.findOne({
where: {
email: req.body.email
}
});
if (exUser) {
return res.status(403).send('이미 사용중인 아이디입니다.');
}
const hashedPassword = await bcrypt.hash(req.body.password, 12);
await User.create({
email: req.body.email,
nickname: req.body.nickname,
password: hashedPassword
});
res.status(201).send('ok');
} catch (error) {
console.error(" 회원 가입 error : ", error);
next(error); //status 500
}
});
module.exports = router;
47. CORS 문제 해결하기
강의 :
백엔드 서버에 cors 설치
npm i cors
app.js
const express = require('express');
const postRouter = require('./routes/posts');
const userRouter = require('./routes/user');
const cors = require('cors');
const db = require('./models');
const app = express();
db.sequelize.sync()
.then(() => {
console.log('db 연결 성공');
})
.catch(console.error);
app.use(cors({
//origin: 'https://nodebird.com'
origin: true, // orign: true 로 설정해두면 * 대신 보낸 곳의 주소가 자동으로 들어가 편리합니다.
credentials: false
}));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
~
CORS?
CORS(Cross Origin Resource Sharing) 는 추가적인 HTTP 헤더를 사용해서
한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 자원에 접근할 수 있는 권한을 관리하는 체제입니다.

즉 위와 같이 domain-a.com 에서 같은 주소의 domain-a.com 에 접근하여 자원을 요청할때는 문제가 발생하지 않지만,
domain-b.com 에 요청할 경우 도메인이 다르기 때문에 보안상의 이유로 제한됩니다.

만약 서버에서 올바른 CORS 헤더를 포함한 응답을 반환하지 않으면 위와 같은 오류가 발생하게 됩니다.
위 예시에서는 자원을 가지고 있는 서버단의 도메인인 http://127.0.0.1:3000 과 자원을 요청한 http://localhost:8080 의 출처가 다르기 때문에 발생한 오류입니다.
Node.js에서 CORS 설정
CORS 패키지 설치
우선 CORS 미들웨어를 사용하기 위해 패키지를 설치합니다.
$npm i cors
모든 CORS Request 허용하기
모든 요청을 허용할 경우 다음과 같이 간단하게 미들웨어를 불러와서 추가해주는 것으로 해결할 수 있습니다.
app.js
const express = require("express");
const cors = require("cors");
const app = express();
app.use(cors()); // CORS 미들웨어 등록
// ...
Whitelist로 특정 주소만 허용하기
모든 CORS 요청을 허용해주는 것이 때로는 보안상의 문제로 이어질 수 있습니다.
만약 특정 호스트만 CORS 요청을 허용해주고 싶다면 다음과 같이 whitelist 를 추가해서 검증하는 방법이 있습니다.
요청을 허용할 주소를 담은 whitelist 를 생성해주고 요청 HTTP 헤더의 Origin 속성을 확인해서
일치하는 항목이 있을 경우 허용해주는 방식입니다.
app.js
const express = require("express");
const cors = require("cors");
const app = express();
const whitelist = ["http://localhost:8080"];
const corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error("Not Allowed Origin!"));
}
},
};
app.use(cors(corsOptions)); // 옵션을 추가한 CORS 미들웨어 추가
// ...참고 자료
- https://expressjs.com/en/resources/middleware/cors.html
- https://developer.mozilla.org/ko/docs/Web/HTTP/CORS
48. 패스포트로 로그인하기.
강의 :
라이브러리 설치
$ npm i passport passport-local $ npm i express-session

app.js
const express = require('express');
const postRouter = require('./routes/posts');
const userRouter = require('./routes/user');
const cors = require('cors');
const db = require('./models');
const passportConfig = require('./passport');
const app = express();
db.sequelize.sync()
.then(() => {
console.log('db 연결 성공');
})
.catch(console.error);
passportConfig();
~
passport/index.js
const passport = require('passport');
const local = require('./local');
module.exports = () => {
passport.serializeUser(() => {
});
passport.deserializeUser(() => {
});
local();
}
passport/local.js
const passport = require('passport');
const { Strategy: LocalStrategey } = require('passport-local');
const bcrypt = require('bcrypt');
const { User } = require('../models');
module.exports = () => {
passport.use(new LocalStrategey({
usernameField: 'email',
passwordField: 'password',
}, async (email, password, done) => {
try {
const user = await User.findOne({
where: { email }
});
if (!user) {
return done(null, false, { reason: '존재하지 않는 사용자입니다.' })
}
const result = await bcrypt.compare(password, user.password);
if (!result) {
return done(null, false, { reason: '비밀번호가 틀렸습니다.' });
}
return done(null, user);
} catch (error) {
console.error(" 로그인 에러 : ", error);
return done(error);
}
}));
}
routes/user.js
const express = require('express');
const { User } = require('../models');
const bcrypt = require('bcrypt');
const passport = require('passport');
const router = express.Router();
//passport.authenticate 미들웨어는 (req, res, next) 사용할수 없는 미들웨어인데 다음과 미들웨어 확장 같은 설정으로 사용
//POST /user/login
router.post('/login', (req, res, next) => {
console.log("로그인 ", req.body);
passport.authenticate('local', (err, user, info) => {
if (err) {
console.error(err);
console.error("1.로그인 에러 ", err);
next(err);
}
//현재 info 가 존재하면 클라이언트 에러
//info 예 => { reason: '존재하지 않는 사용자입니다.' } { reason: '비밀번호가 틀렸습니다.' }
if (info) {
//401 허가되지 않음 403 금지
return res.status(401).send(info.reason);
}
return req.login(user, async (loginErr) => {
if (loginErr) {
console.error("2.로그인 에러 ", loginErr);
return next(loginErr);
}
return res.status(200).json(user)
});
})(req, res, next);
});
~
49. 쿠키/세션과 전체 로그인 흐름.
강의 :

라이브러리 추가
$ npm i cookie-parser $ npm i dotenv
app.js 다음 4가지 추가
app.use(cookieParser); app.use(session()); app.use(passport.initialize()); app.use(passport.session());
app.js => routes/user.js => passport/index.js 에서 local 함수 실행 = > passport/local.js
app.js =>
const express = require('express');
const postRouter = require('./routes/posts');
const userRouter = require('./routes/user');
const cors = require('cors');
const db = require('./models');
const passportConfig = require('./passport');
const passport = require('passport');
const session = require("express-session");
const cookieParser = require('cookie-parser');
const dotenv = require('dotenv');
dotenv.config();
const app = express();
db.sequelize.sync()
.then(() => {
console.log('db 연결 성공');
})
.catch(console.error);
app.use(cors({
//origin: 'https://nodebird.com'
origin: true, // orign: true 로 설정해두면 * 대신 보낸 곳의 주소가 자동으로 들어가 편리합니다.
credentials: false
}));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(session({
secret: process.env.COOKIE_SECRET,
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize()); //패스포트 초기화
app.use(passport.session());
passportConfig();
app.get('/', (req, res) => {
res.send('hello express');
});
app.get('/api', (req, res) => {
res.send('hello api');
});
app.get('/api/posts', (req, res) => {
res.json([
{ id: 1, content: 'hello1' },
{ id: 2, content: 'hello2' },
{ id: 3, content: 'hello3' }
])
});
app.use('/post', postRouter);
app.use('/user', userRouter);
app.listen(3065, () => {
console.log("서버 실행 중");
});
routes/user.js
const express = require('express');
const { User } = require('../models');
const bcrypt = require('bcrypt');
const passport = require('passport');
const router = express.Router();
//passport.authenticate 미들웨어는 (req, res, next) 사용할수 없는 미들웨어인데 다음과 미들웨어 확장 같은 설정으로 사용
//POST /user/login
router.post('/login', (req, res, next) => {
console.log("로그인 ", req.body);
passport.authenticate('local', (err, user, info) => {
if (err) {
console.error(err);
console.error("1.로그인 에러 ", err);
next(err);
}
//현재 info 가 존재하면 클라이언트 에러
//info 예 => { reason: '존재하지 않는 사용자입니다.' } { reason: '비밀번호가 틀렸습니다.' }
if (info) {
//401 허가되지 않음 403 금지
return res.status(401).send(info.reason);
}
console.log("3 passport .req.login 실행 : ", user);
return req.login(user, async (loginErr) => {
console.log("로그인 처리 ");
if (loginErr) {
console.error("2.로그인 에러 ", loginErr);
return next(loginErr);
}
console.log("로그인 성공 : ", user);
return res.status(200).json(user)
});
})(req, res, next);
});
//로그아웃
router.post('/logout', (req, res, next) => {
req.logout(function (err) {
if (err) { return next(err); }
req.session.destroy();
res.send('ok')
});
});
~
passport/index.js
const passport = require('passport');
const local = require('./local');
const { User } = require('../models');
module.exports = () => {
passport.serializeUser((user, done) => {
//메모리에 많은 양의 데이터를 저장하면 메모리 낭비가 심하므로 user id 만 저장 한다.
done(null, user.id);
});
//user id 를 통해 user 정보를 가져온다.
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findOne({ where: { id } })
done(null, user); //req.user 저장
} catch (error) {
console.error(" passport.deserializeUser error : ", error);
done(error);
}
});
local();
}
passport/local.js
const passport = require('passport');
const { Strategy: LocalStrategey } = require('passport-local');
const bcrypt = require('bcrypt');
const { User } = require('../models');
module.exports = () => {
console.log(" passport local.js module.exports ");
passport.use(new LocalStrategey({
usernameField: 'email',
passwordField: 'password',
}, async (email, password, done) => {
try {
const user = await User.findOne({
where: { email }
});
if (!user) {
return done(null, false, { reason: '존재하지 않는 사용자입니다.' })
}
const result = await bcrypt.compare(password, user.password);
if (!result) {
return done(null, false, { reason: '비밀번호가 틀렸습니다.' });
}
return done(null, user);
} catch (error) {
console.error(" 로그인 에러 : ", error);
return done(error);
}
}));
}
dotenv 설정
.env
COOKIE_SECRET=1123@2312dajfj23rj2po4$#%@# DB_PASSWORD=1234
config/config.js
const dotenv = require('dotenv');
dotenv.config();
module.exports = {
"development": {
"username": "react-nodebird",
"password": process.env.DB_PASSWORD,
"database": "react_nodebird",
"host": "127.0.0.1",
"post": "3306",
"dialect": "mysql"
},
"test": {
"username": "react-nodebird",
"password": process.env.DB_PASSWORD,
"database": "react_nodebird",
"host": "127.0.0.1",
"post": "3306",
"dialect": "mysql"
},
"production": {
"username": "react-nodebird",
"password": process.env.DB_PASSWORD,
"database": "react_nodebird",
"host": "127.0.0.1",
"post": "3306",
"dialect": "mysql"
}
}
50. 로그인 문제 해결하기
강의 :
로그인시 유저정보 뿐만 아니라 Post 및 Followers 및 Followings 데이터를 가져오는 것때문에 오류
routes/user.js
const express = require('express');
const { User, Post } = require('../models');
const bcrypt = require('bcrypt');
const passport = require('passport');
const router = express.Router();
//passport.authenticate 미들웨어는 (req, res, next) 사용할수 없는 미들웨어인데 다음과 미들웨어 확장 같은 설정으로 사용
//POST /user/login
router.post('/login', (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if (err) {
console.error(err);
console.error("1.로그인 에러 ", err);
next(err);
}
//현재 info 가 존재하면 클라이언트 에러 메시지 반환처리
//info 예 => { reason: '존재하지 않는 사용자입니다.' } { reason: '비밀번호가 틀렸습니다.' }
if (info) {
//401 허가되지 않음 403 금지
return res.status(401).send(info.reason);
}
return req.login(user, async (loginErr) => {
if (loginErr) {
return next(loginErr);
}
const fullUserWithoutPassword = await User.findOne({
where: {
id: user.id
},
//원하는 정보만 attributes: ['id', 'nickname', 'email'],
attributes: {
exclude: ['password']
},
include: [{
model: Post
}, {
model: User,
as: "Followers"
},
{
model: User,
as: "Followings"
}
]
})
return res.status(200).json(fullUserWithoutPassword)
});
})(req, res, next);
});
//로그아웃
router.post('/logout', (req, res, next) => {
req.logout(function (err) {
if (err) { return next(err); }
req.session.destroy();
res.send('ok')
});
});
router.post('/', async (req, res, next) => {
try {
console.log(" 백엔드 : ", req.body);
const exUser = await User.findOne({
where: {
email: req.body.email
}
});
if (exUser) {
return res.status(403).send('이미 사용중인 아이디 입니다.');
}
const hashedPassword = await bcrypt.hash(req.body.password, 12);
await User.create({
email: req.body.email,
nickname: req.body.nickname,
password: hashedPassword
});
//res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3060'); //특정서버
// res.setHeader('Access-Control-Allow-Origin', '*'); //모든서버
res.status(201).send('ok');
} catch (error) {
console.error(" 회원 가입 error : ", error);
next(error); //status 500
}
});
module.exports = router;
프론트 엔드 nextjs 에서 다음과 같이 처리
components/LoginForm.js
import React, { useCallback , useEffect} from 'react';
import { Form, Input, Button } from 'antd';
import styled from 'styled-components';
import Link from 'next/link';
import useInput from '../hooks/useInput';
import { useDispatch, useSelector } from 'react-redux';
import { loginRequestAction } from './../reducers/user';
const ButtonWrapper = styled.div`
margin-top:10px
`;
const FormWrapper = styled(Form)`
margin-top: 5px;
padding:10px;
`;
const LoginForm = () => {
const dispatch = useDispatch();
const { logInLoading, logInError } = useSelector((state) => state.user);
const [email, onChangeEmail] = useInput('');
const [password, onChangePassword] = useInput('');
useEffect(() => {
if(logInError){
alert(logInError);
}
}, [logInError]);
~
뒤로가기 못하게 Router.replace('/');
Router.push("/");
=>
Router.replace("/");
pages/signup.js
~
const SignUp = () => {
const dispatch = useDispatch();
const { signUpLoading, signUpDone, signUpError, me } = useSelector((state) => state.user);
const { schema } = useSimpleValidation();
const [joinState, setJoinState] = useState(true);
useEffect(() => {
if (me && me.id) {
Router.replace("/");
}
}, [me && me.id]);
~
51. 미들웨어로 라우터 검사하기
강의 :

로그인 했는지 안했는지 검사하는 미들웨어 만들기
routes/middlewares.js
exports.isLoggedIn = (req, res, next) => {
// 패스포트에서 isAuthenticated 를 제공한다
if (req.isAuthenticated()) {
next();
} else {
res.status(401).send('로그인이 필요합니다.');
}
}
exports.isNotLoggedIn = (req, res, next) => {
if (!req.isAuthenticated()) {
next();
} else {
res.status(401).send('로그인하지 않은 사용자만 접근 가능합니다.');
}
}
로그인 유무 처리 미들웨어 적용
router.post('/login', isNotLoggedIn, (req, res, next) => {
~
//로그아웃
router.post('/logout', isLoggedIn, (req, res, next) => {
~routes/user.js
const express = require('express');
const { User, Post } = require('../models');
const bcrypt = require('bcrypt');
const passport = require('passport');
const router = express.Router();
const { isLoggedIn, isNotLoggedIn } = require('./middlewares');
//passport.authenticate 미들웨어는 (req, res, next) 사용할수 없는 미들웨어인데 다음과 미들웨어 확장 같은 설정으로 사용
//POST /user/login
router.post('/login', isNotLoggedIn, (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if (err) {
console.error(err);
console.error("1.로그인 에러 ", err);
next(err);
}
//현재 info 가 존재하면 클라이언트 에러 메시지 반환처리
//info 예 => { reason: '존재하지 않는 사용자입니다.' } { reason: '비밀번호가 틀렸습니다.' }
if (info) {
//401 허가되지 않음 403 금지
return res.status(401).send(info.reason);
}
return req.login(user, async (loginErr) => {
if (loginErr) {
return next(loginErr);
}
const fullUserWithoutPassword = await User.findOne({
where: {
id: user.id
},
//원하는 정보만 attributes: ['id', 'nickname', 'email'],
attributes: {
exclude: ['password']
},
include: [{
model: Post
}, {
model: User,
as: "Followers"
},
{
model: User,
as: "Followings"
}
]
})
return res.status(200).json(fullUserWithoutPassword)
});
})(req, res, next);
});
//로그아웃
router.post('/logout', isLoggedIn, (req, res, next) => {
req.logout(function (err) {
if (err) { return next(err); }
req.session.destroy();
res.send('ok')
});
});
router.post('/', isNotLoggedIn, async (req, res, next) => {
try {
console.log(" 백엔드 : ", req.body);
const exUser = await User.findOne({
where: {
email: req.body.email
}
});
if (exUser) {
return res.status(403).send('이미 사용중인 아이디 입니다.');
}
const hashedPassword = await bcrypt.hash(req.body.password, 12);
await User.create({
email: req.body.email,
nickname: req.body.nickname,
password: hashedPassword
});
//res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3060'); //특정서버
// res.setHeader('Access-Control-Allow-Origin', '*'); //모든서버
res.status(201).send('ok');
} catch (error) {
console.error(" 회원 가입 error : ", error);
next(error); //status 500
}
});
module.exports = router;
52. 게시글, 댓글 작성하기
강의 :
백엔드
routes/posts.js
const express = require('express');
const { Post } = require('../models');
const { isLoggedIn, isNotLoggedIn } = require('./middlewares');
const router = express.Router();
//** passport 특성상 로그인 하면, 라우터 접근시 항상 deserializeUser 실행해서 req.user 를 만든다. req.user.id로 접근해서 정보를 가져올 수 있다.
//POST /post
router.post('/', isLoggedIn, async (req, res, next) => {
try {
const post = await Post.create({
content: req.body.content,
UserId: req.user.id
});
res.status(201).json(post);
} catch (error) {
console.error(" Post 에러 : ", error);
next(error);
}
});
//POST 댓글 /post
router.post('/:postId/comment', isLoggedIn, async (req, res, next) => { //POST /post/1/comment
try {
const post = await Post.findOne({
where: { id: req.params.postId }
});
if (!post) {
return res.status(403).send("존재하지 않는 게시글입니다.");
}
const comment = await Post.create({
content: req.body.content,
PostId: req.params.postId,
UserId: req.user.id
});
res.status(201).json(comment);
} catch (error) {
console.error(" comment 에러 : ", error);
next(error);
}
});
//DELETE /post
router.delete('/', (req, res) => {
res.json({ id: 1 })
});
module.exports = router;
프론트엔드
front/reducers/post.js
~
//글작성
case ADD_POST_REQUEST:
draft.addPostLoading = true;
draft.addPostDone = false;
draft.addPostError = null;
break;
case ADD_POST_SUCCESS:
draft.addPostLoading = false;
draft.addPostDone = true;
draft.mainPosts.unshift(action.data);
break;
case ADD_POST_FAILURE:
draft.addPostLoading = false;
draft.addPostError = action.error;
break;
~
front/saga/post.js
~
//3-1. 글작성
function addPostAPI(data) {
return axios.post('/post', { content: data });
}
//3-2.
function* addPost(action) {
try {
const result = yield call(addPostAPI, action.data);
console.log("2. 게시글 등록 후 반환 : ", result);
yield put({
type: ADD_POST_SUCCESS,
data: result.data
});
yield put({
type: ADD_POST_TO_ME,
data: result.data.id
})
} catch (err) {
yield put({
type: ADD_POST_FAILURE,
error: err.response.data
});
}
}
//댓글
function addCommentAPI(data) {
return axios.Comment(`/post/${data.postId}/comment`, data); //POST post/1/comment
}
function* addComment(action) {
try {
const result = yield call(addCommentAPI, action.data);
yield put({
type: ADD_COMMENT_SUCCESS,
data: result.data
});
} catch (err) {
yield put({
type: ADD_COMMENT_FAILURE,
error: err.response.data
});
}
}
function* watchAddComment() {
yield takeLatest(ADD_COMMENT_REQUEST, addComment);
}
53. credentials로 쿠키 공유하기
강의 :
도메인 URL이 다르면 쿠키전달도 안된다.
cros 처리는 proxy 를 이용한 방법
백엔드에서 다음과 같이 credentials 에서 true 처리를 하여 쿠키 공유
app.js
app.use(cors({
//origin: 'https://nodebird.com'
origin: 'http://localhost:3060', // orign: true 로 설정해두면 * 대신 보낸 곳의 주소가 자동으로 들어가 편리합니다.
credentials: true
}));
origin : true 하면 로그인 오류로 안된다.
프론트엔드에서 다음과 같이
axios.defaults.withCredentials = true;
saga/index.js
import { all, fork } from 'redux-saga/effects';
import axios from 'axios';
import postSaga from './post';
import userSaga from './user';
axios.defaults.baseURL = 'http://localhost:3065';
axios.defaults.withCredentials = true;
export default function* rootSaga() {
yield all([
fork(postSaga),
fork(userSaga),
]);
}
백엔드
routes/posts.js
const express = require('express');
const { Post, User, Image, Comment } = require('../models');
const { isLoggedIn, isNotLoggedIn } = require('./middlewares');
const router = express.Router();
//** passport 특성상 로그인 하면, 라우터 접근시 항상 deserializeUser 실행해서 req.user 를 만든다. req.user.id로 접근해서 정보를 가져올 수 있다.
//POST /post
router.post('/', isLoggedIn, async (req, res, next) => {
try {
const post = await Post.create({
content: req.body.content,
UserId: req.user.id
});
const fullPost = await Post.findOne({
where: { id: post.id },
include: [{
model: Image,
},
{
model: Comment
}, {
model: User,
}
]
})
res.status(201).json(fullPost);
} catch (error) {
console.error(" Post 에러 : ", error);
next(error);
}
});
~
54. 내 로그인 정보 매번 불러오기
강의:
백엔드
routes/user.js
const express = require('express');
const { User, Post } = require('../models');
const bcrypt = require('bcrypt');
const passport = require('passport');
const router = express.Router();
const { isLoggedIn, isNotLoggedIn } = require('./middlewares');
//브라우저에서 새로고침 할때마다 요청처리 된다.
router.get('/', async (req, res, next) => {
try {
if (req.user) {
const fullUserWithoutPassword = await User.findOne({
where: {
id: req.user.id
},
attributes: {
exclude: ['password']
},
include: [{
model: Post,
attributes: ['id'],
}, {
model: User,
as: "Followers",
attributes: ['id'],
},
{
model: User,
as: "Followings",
attributes: ['id'],
}
]
})
res.status(200).json(fullUserWithoutPassword);
} else {
res.status(200).json(null);
}
} catch (error) {
console.error("/ 쿠키 정보 가져오기 에러 : ", error);
next(error);
}
});
~
프론트엔드
pages/index.js
import React, { useEffect, useCallback } from 'react';
import AppLayout from './../components/AppLayout';
import { useSelector, useDispatch } from 'react-redux';
import PostCard from './../components/PostCard';
import PostForm from './../components/PostForm';
import { LOAD_MY_INFO_REQUEST } from './../reducers/user';
import { LOAD_POSTS_REQUEST } from './../reducers/post';
const Index = () => {
const dispatch = useDispatch();
const { me } = useSelector((state) => state.user);
const { mainPosts, hasMorePosts, loadPostsLoading } = useSelector((state) => state.post);
useEffect(() => {
dispatch({
type: LOAD_MY_INFO_REQUEST
});
dispatch({
type: LOAD_POSTS_REQUEST
});
}, []);
~
reducers/user.js
import produce from "immer";
export const initialState = {
~
loadMyInfoLoading: false, //브라우저 새로고침시 유저정보 가져오기
loadMyInfoDone: false,
loadMyInfoError: null,
me: null,
signUpdata: {},
loginData: {}
}
export const LOAD_MY_INFO_REQUEST = "LOAD_MY_INFO_REQUEST";
export const LOAD_MY_INFO_SUCCESS = "LOAD_MY_INFO_SUCCESS";
export const LOAD_MY_INFO_FAILURE = "LOAD_MY_INFO_FAILURE";
~
const reducer = (state = initialState, action) => produce(state, (draft) => {
switch (action.type) {
//브라우저 새로고침시 유저정보 가져오기
case LOAD_MY_INFO_REQUEST:
draft.loadMyInfoLoading = true;
draft.loadMyInfoDone = false;
draft.loadMyInfoError = null;
break;
case LOAD_MY_INFO_SUCCESS:
draft.loadMyInfoLoading = false;
draft.loadMyInfoDone = true;
draft.me=action.data
break;
case LOAD_MY_INFO_FAILURE:
draft.loadMyInfoLoading = false;
draft.loadMyInfoError = action.error;
break;
~
saga/user.js
import { all, fork, put, takeLatest, delay, call, throttle } from 'redux-saga/effects';
import axios from 'axios';
import {
LOG_IN_REQUEST, LOG_IN_SUCCESS, LOG_IN_FAILURE,
LOG_OUT_REQUEST, LOG_OUT_SUCCESS, LOG_OUT_FAILURE,
SIGN_UP_REQUEST, SIGN_UP_SUCCESS, SIGN_UP_FAILURE,
FOLLOW_REQUEST, FOLLOW_SUCCESS, FOLLOW_FAILURE,
UNFOLLOW_REQUEST, UNFOLLOW_SUCCESS, UNFOLLOW_FAILURE,
LOAD_MY_INFO_REQUEST, LOAD_MY_INFO_SUCCESS, LOAD_MY_INFO_FAILURE
} from '../reducers/user';
//브라우저 새로고침시 유저정보 가져오기
function loadMyInfoAPI() {
return axios.get('/user');
}
function* loadMyInfo(action) {
try {
const result = yield call(loadMyInfoAPI)
yield put({
type: LOAD_MY_INFO_SUCCESS,
data: result.data
});
} catch (err) {
yield put({
type: LOAD_MY_INFO_FAILURE,
error: err.response.data
});
}
}
function* watchLoadMyInfo() {
yield takeLatest(LOAD_MY_INFO_REQUEST, loadMyInfo);
}
~
//all 하면 한방에 배열로 적은 함수들이 실행처리 된다.
//fork , call 로 실행한다. all 은 fork 나 call 을 동시에 실행시키도록 한다.
//call 은 동기 함수 호출
//fork 는 비동기 함수 호출
export default function* userSaga() {
yield all([
fork(watchLogIn),
fork(watchLogOut),
fork(watchFollow),
fork(watchUnFollow),
fork(watchSignUp),
fork(watchLoadMyInfo),
])
}














댓글 ( 4)
댓글 남기기