Category: 블로그

0

리엑트 블로그 만들기 15 - Post Card List 만들기 2

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 15 - Post Card List 만들기 2import { POSTS_LOADING_FAILURE, POSTS_LOADING_REQUEST, POSTS_LOADING_SUCCESS } from "../types";const initialState = { isAuthenticated: null, posts: [], postDetails: "", postCount: "", loading: false, error: "", creatorId: "", categoryFindResult: "", title: "", searchBy: "", searchResult: "",};export default function postReducer(state = initialState, action) { switch (action.type) { case POSTS_LOADING_REQUEST: return { ...state, posts: [], loading: true, } case POSTS_LOADING_SUCCESS: return { ...state, posts: [...state.posts, ...action.payload], loading: false, }; case POSTS_LOADING_FAILURE: return { ...state, loading: false, }; default: return state; };} // POST WRITEexport const POSTS_WRITE_REQUEST = "POST_WRITE_REQUEST";export const POSTS_WRITE_FAILURE = "POST_WRITE_FAILURE";export const POSTS_WRITE_SUCCESS = "POST_WRITE_SUCCESS";// POST LOADINGexport const POSTS_LOADING_REQUEST = "POST_LOADING_REQUEST";export const POSTS_LOADING_FAILURE = "POST_LOADING_FAILURE";export const POSTS_LOADING_SUCCESS = "POST_LOADING_SUCCESS"; import { combineReducers } from "redux";import { connectRouter } from "connected-react-router";import authReducer from "./authReducer.js";import postReducer from "./postReducer.js";import commentReducer from "./commentReducer.js";const createRootReducer = (history) => combineReducers({ router: connectRouter(history), auth: authReducer, post: postReducer, comment: commentReducer, });export default createRootReducer; import axios from "axios";import { put, call, takeEvery, all, fork } from "redux-saga/effects";import { push } from "connected-react-router";import { POSTS_LOADING_FAILURE, POSTS_LOADING_SUCCESS, POSTS_LOADING_REQUEST, POST_UPLOADING_SUCCESS, POST_UPLOADING_FAILURE, POST_UPLOADING_REQUEST, POST_DETAIL_LOADING_SUCCESS, POST_DETAIL_LOADING_FAILURE, POST_DETAIL_LOADING_REQUEST, POST_DELETE_SUCCESS, POST_DELETE_FAILURE, POST_DELETE_REQUEST, POST_EDIT_LOADING_SUCCESS, POST_EDIT_LOADING_FAILURE, POST_EDIT_UPLOADING_SUCCESS, POST_EDIT_UPLOADING_FAILURE, POST_EDIT_UPLOADING_REQUEST, POST_EDIT_LOADING_REQUEST, CATEGORY_FIND_FAILURE, CATEGORY_FIND_SUCCESS, CATEGORY_FIND_REQUEST, SEARCH_SUCCESS, SEARCH_FAILURE, SEARCH_REQUEST,} from "../types";// All Posts loadconst loadPostAPI = (payload) => { return axios.get(`/api/post/skip/${payload}`);};function* loadPosts(action) { try { const result = yield call(loadPostAPI, action.payload); console.log(result, "loadPosts"); yield put({ type: POSTS_LOADING_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: POSTS_LOADING_FAILURE, payload: e, }); }}function* watchLoadPosts() { yield takeEvery(POSTS_LOADING_REQUEST, loadPosts);}// Post Uploadconst uploadPostAPI = (payload) => { const config = { headers: { "Content-Type": "application/json", }, }; const token = payload.token; if (token) { config.headers["x-auth-token"] = token; } return axios.post("/api/post", payload, config);};function* uploadPosts(action) { try { console.log(action, "uploadPost function"); const result = yield call(uploadPostAPI, action.payload); console.log(result, "uploadPostAPI, action.payload"); yield put({ type: POST_UPLOADING_SUCCESS, payload: result.data, }); yield put(push(`/post/${result.data._id}`)); } catch (e) { yield put({ type: POST_UPLOADING_FAILURE, payload: e, }); yield put(push("/")); }}function* watchuploadPosts() { yield takeEvery(POST_UPLOADING_REQUEST, uploadPosts);}// Post Detailconst loadPostDetailAPI = (payload) => { console.log(payload); return axios.get(`/api/post/${payload}`);};function* loadPostDetail(action) { try { console.log(action); const result = yield call(loadPostDetailAPI, action.payload); console.log(result, "post_detail_saga_data"); yield put({ type: POST_DETAIL_LOADING_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: POST_DETAIL_LOADING_FAILURE, payload: e, }); yield put(push("/")); }}function* watchloadPostDetail() { yield takeEvery(POST_DETAIL_LOADING_REQUEST, loadPostDetail);}// Post Deleteconst DeletePostAPI = (payload) => { const config = { headers: { "Content-Type": "application/json", }, }; const token = payload.token; if (token) { config.headers["x-auth-token"] = token; } return axios.delete(`/api/post/${payload.id}`, config);};function* DeletePost(action) { try { const result = yield call(DeletePostAPI, action.payload); yield put({ type: POST_DELETE_SUCCESS, payload: result.data, }); yield put(push("/")); } catch (e) { yield put({ type: POST_DELETE_FAILURE, payload: e, }); }}function* watchDeletePost() { yield takeEvery(POST_DELETE_REQUEST, DeletePost);}// Post Edit Loadconst PostEditLoadAPI = (payload) => { const config = { headers: { "Content-Type": "application/json", }, }; const token = payload.token; if (token) { config.headers["x-auth-token"] = token; } return axios.get(`/api/post/${payload.id}/edit`, config);};function* PostEditLoad(action) { try { const result = yield call(PostEditLoadAPI, action.payload); yield put({ type: POST_EDIT_LOADING_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: POST_EDIT_LOADING_FAILURE, payload: e, }); yield put(push("/")); }}function* watchPostEditLoad() { yield takeEvery(POST_EDIT_LOADING_REQUEST, PostEditLoad);}// Post Edit UpLoadconst PostEditUploadAPI = (payload) => { const config = { headers: { "Content-Type": "application/json", }, }; const token = payload.token; if (token) { config.headers["x-auth-token"] = token; } return axios.post(`/api/post/${payload.id}/edit`, payload, config);};function* PostEditUpload(action) { try { const result = yield call(PostEditUploadAPI, action.payload); yield put({ type: POST_EDIT_UPLOADING_SUCCESS, payload: result.data, }); yield put(push(`/post/${result.data._id}`)); } catch (e) { yield put({ type: POST_EDIT_UPLOADING_FAILURE, payload: e, }); }}function* watchPostEditUpload() { yield takeEvery(POST_EDIT_UPLOADING_REQUEST, PostEditUpload);}// Category Findconst CategoryFindAPI = (payload) => { return axios.get(`/api/post/category/${encodeURIComponent(payload)}`);};function* CategoryFind(action) { try { const result = yield call(CategoryFindAPI, action.payload); yield put({ type: CATEGORY_FIND_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: CATEGORY_FIND_FAILURE, payload: e, }); }}function* watchCategoryFind() { yield takeEvery(CATEGORY_FIND_REQUEST, CategoryFind);}// Search Findconst SearchResultAPI = (payload) => { return axios.get(`/api/search/${encodeURIComponent(payload)}`);};function* SearchResult(action) { try { const result = yield call(SearchResultAPI, action.payload); yield put({ type: SEARCH_SUCCESS, payload: result.data, }); yield put(push(`/search/${encodeURIComponent(action.payload)}`)); } catch (e) { yield put({ type: SEARCH_FAILURE, payload: e, }); yield put(push("/")); }}function* watchSearchResult() { yield takeEvery(SEARCH_REQUEST, SearchResult);}export default function* postSaga() { yield all([ fork(watchLoadPosts), fork(watchuploadPosts), fork(watchloadPostDetail), fork(watchDeletePost), fork(watchPostEditLoad), fork(watchPostEditUpload), fork(watchCategoryFind), fork(watchSearchResult), ]);} import React, { Fragment } from "react";import { Row, Spinner } from "reactstrap";export const GrowingSpinner = ( <Fragment> <Row className="d-flex justify-content-center m-5"> <Spinner style={{ width: "2rem", height: "2rem" }} type="grow" color="primary" /> <Spinner style={{ width: "2rem", height: "2rem" }} type="grow" color="secondary" /> <Spinner style={{ width: "2rem", height: "2rem" }} type="grow" color="success" /> <Spinner style={{ width: "2rem", height: "2rem" }} type="grow" color="danger" /> <Spinner style={{ width: "2rem", height: "2rem" }} type="grow" color="warning" /> <Spinner style={{ width: "2rem", height: "2rem" }} type="grow" color="info" /> <Spinner style={{ width: "2rem", height: "2rem" }} type="grow" color="light" /> <Spinner style={{ width: "2rem", height: "2rem" }} type="grow" color="dark" /> </Row> </Fragment>); import React, { Fragment } from "react";import { Card, CardImg, CardBody, CardTitle, Button, Badge, Row,} from "reactstrap";import { Link } from "react-router-dom";import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";import { faMouse } from "@fortawesome/free-solid-svg-icons";const PostCardOne = ({ posts }) => { return ( <Fragment> {Array.isArray(posts) ? posts.map(({ _id, title, fileUrl, comments, views }) => { return ( <div key={_id} className="col-md-4"> <Link to={`/post/${_id}`} className="text-dark text-decoration-none" > <Card className="mb-3"> <CardImg top alt="카드이미지" src={fileUrl} /> <CardBody> <CardTitle className="text-truncate d-flex justify-content-between"> <span className="text-truncate">{title} </span> <span> <FontAwesomeIcon icon={faMouse} /> &nbsp;&nbsp; <span>{views}</span> </span> </CardTitle> <Row> <Button color="primary" className="p-2 btn-block"> More <Badge color="light">{comments.length}</Badge> </Button> </Row> </CardBody> </Card> </Link> </div> ); }) : ""} </Fragment> );};export default PostCardOne;

0

리엑트 블로그 만들기 14 - Post Card List 만들기

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 14 - Post Card List 만들기import { POSTS_LOADING_FAILURE, POSTS_LOADING_REQUEST, POSTS_LOADING_SUCCESS } from "../types";const initialState = { isAuthenticated: null, posts: [], postDetails: "", postCount: "", loading: false, error: "", creatorId: "", categoryFindResult: "", title: "", searchBy: "", searchResult: "",};export default function postReducer(state = initialState, action) { switch (action.type) { case POSTS_LOADING_REQUEST: return { ...state, posts: [], loading: true, } case POSTS_LOADING_SUCCESS: return { ...state, posts: [...state.posts, ...action.payload], loading: false, }; case POSTS_LOADING_FAILURE: return { ...state, loading: false, }; default: return state; };} // POST WRITEexport const POSTS_WRITE_REQUEST = "POST_WRITE_REQUEST";export const POSTS_WRITE_FAILURE = "POST_WRITE_FAILURE";export const POSTS_WRITE_SUCCESS = "POST_WRITE_SUCCESS";// POST LOADINGexport const POSTS_LOADING_REQUEST = "POST_LOADING_REQUEST";export const POSTS_LOADING_FAILURE = "POST_LOADING_FAILURE";export const POSTS_LOADING_SUCCESS = "POST_LOADING_SUCCESS"; import { combineReducers } from "redux";import { connectRouter } from "connected-react-router";import authReducer from "./authReducer.js";import postReducer from "./postReducer.js";import commentReducer from "./commentReducer.js";const createRootReducer = (history) => combineReducers({ router: connectRouter(history), auth: authReducer, post: postReducer, comment: commentReducer, });export default createRootReducer; import axios from "axios";import { put, call, takeEvery, all, fork } from "redux-saga/effects";import { push } from "connected-react-router";import { POSTS_LOADING_FAILURE, POSTS_LOADING_SUCCESS, POSTS_LOADING_REQUEST, POST_UPLOADING_SUCCESS, POST_UPLOADING_FAILURE, POST_UPLOADING_REQUEST, POST_DETAIL_LOADING_SUCCESS, POST_DETAIL_LOADING_FAILURE, POST_DETAIL_LOADING_REQUEST, POST_DELETE_SUCCESS, POST_DELETE_FAILURE, POST_DELETE_REQUEST, POST_EDIT_LOADING_SUCCESS, POST_EDIT_LOADING_FAILURE, POST_EDIT_UPLOADING_SUCCESS, POST_EDIT_UPLOADING_FAILURE, POST_EDIT_UPLOADING_REQUEST, POST_EDIT_LOADING_REQUEST, CATEGORY_FIND_FAILURE, CATEGORY_FIND_SUCCESS, CATEGORY_FIND_REQUEST, SEARCH_SUCCESS, SEARCH_FAILURE, SEARCH_REQUEST,} from "../types";// All Posts loadconst loadPostAPI = (payload) => { return axios.get(`/api/post/skip/${payload}`);};function* loadPosts(action) { try { const result = yield call(loadPostAPI, action.payload); console.log(result, "loadPosts"); yield put({ type: POSTS_LOADING_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: POSTS_LOADING_FAILURE, payload: e, }); }}function* watchLoadPosts() { yield takeEvery(POSTS_LOADING_REQUEST, loadPosts);}// Post Uploadconst uploadPostAPI = (payload) => { const config = { headers: { "Content-Type": "application/json", }, }; const token = payload.token; if (token) { config.headers["x-auth-token"] = token; } return axios.post("/api/post", payload, config);};function* uploadPosts(action) { try { console.log(action, "uploadPost function"); const result = yield call(uploadPostAPI, action.payload); console.log(result, "uploadPostAPI, action.payload"); yield put({ type: POST_UPLOADING_SUCCESS, payload: result.data, }); yield put(push(`/post/${result.data._id}`)); } catch (e) { yield put({ type: POST_UPLOADING_FAILURE, payload: e, }); yield put(push("/")); }}function* watchuploadPosts() { yield takeEvery(POST_UPLOADING_REQUEST, uploadPosts);}// Post Detailconst loadPostDetailAPI = (payload) => { console.log(payload); return axios.get(`/api/post/${payload}`);};function* loadPostDetail(action) { try { console.log(action); const result = yield call(loadPostDetailAPI, action.payload); console.log(result, "post_detail_saga_data"); yield put({ type: POST_DETAIL_LOADING_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: POST_DETAIL_LOADING_FAILURE, payload: e, }); yield put(push("/")); }}function* watchloadPostDetail() { yield takeEvery(POST_DETAIL_LOADING_REQUEST, loadPostDetail);}// Post Deleteconst DeletePostAPI = (payload) => { const config = { headers: { "Content-Type": "application/json", }, }; const token = payload.token; if (token) { config.headers["x-auth-token"] = token; } return axios.delete(`/api/post/${payload.id}`, config);};function* DeletePost(action) { try { const result = yield call(DeletePostAPI, action.payload); yield put({ type: POST_DELETE_SUCCESS, payload: result.data, }); yield put(push("/")); } catch (e) { yield put({ type: POST_DELETE_FAILURE, payload: e, }); }}function* watchDeletePost() { yield takeEvery(POST_DELETE_REQUEST, DeletePost);}// Post Edit Loadconst PostEditLoadAPI = (payload) => { const config = { headers: { "Content-Type": "application/json", }, }; const token = payload.token; if (token) { config.headers["x-auth-token"] = token; } return axios.get(`/api/post/${payload.id}/edit`, config);};function* PostEditLoad(action) { try { const result = yield call(PostEditLoadAPI, action.payload); yield put({ type: POST_EDIT_LOADING_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: POST_EDIT_LOADING_FAILURE, payload: e, }); yield put(push("/")); }}function* watchPostEditLoad() { yield takeEvery(POST_EDIT_LOADING_REQUEST, PostEditLoad);}// Post Edit UpLoadconst PostEditUploadAPI = (payload) => { const config = { headers: { "Content-Type": "application/json", }, }; const token = payload.token; if (token) { config.headers["x-auth-token"] = token; } return axios.post(`/api/post/${payload.id}/edit`, payload, config);};function* PostEditUpload(action) { try { const result = yield call(PostEditUploadAPI, action.payload); yield put({ type: POST_EDIT_UPLOADING_SUCCESS, payload: result.data, }); yield put(push(`/post/${result.data._id}`)); } catch (e) { yield put({ type: POST_EDIT_UPLOADING_FAILURE, payload: e, }); }}function* watchPostEditUpload() { yield takeEvery(POST_EDIT_UPLOADING_REQUEST, PostEditUpload);}// Category Findconst CategoryFindAPI = (payload) => { return axios.get(`/api/post/category/${encodeURIComponent(payload)}`);};function* CategoryFind(action) { try { const result = yield call(CategoryFindAPI, action.payload); yield put({ type: CATEGORY_FIND_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: CATEGORY_FIND_FAILURE, payload: e, }); }}function* watchCategoryFind() { yield takeEvery(CATEGORY_FIND_REQUEST, CategoryFind);}// Search Findconst SearchResultAPI = (payload) => { return axios.get(`/api/search/${encodeURIComponent(payload)}`);};function* SearchResult(action) { try { const result = yield call(SearchResultAPI, action.payload); yield put({ type: SEARCH_SUCCESS, payload: result.data, }); yield put(push(`/search/${encodeURIComponent(action.payload)}`)); } catch (e) { yield put({ type: SEARCH_FAILURE, payload: e, }); yield put(push("/")); }}function* watchSearchResult() { yield takeEvery(SEARCH_REQUEST, SearchResult);}export default function* postSaga() { yield all([ fork(watchLoadPosts), fork(watchuploadPosts), fork(watchloadPostDetail), fork(watchDeletePost), fork(watchPostEditLoad), fork(watchPostEditUpload), fork(watchCategoryFind), fork(watchSearchResult), ]);}

0

리엑트 블로그 만들기 13 - 라우트

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 13 - 라우트import React from 'react';const CategoryResult = () => { return <h1>CategoryResult</h1>}export default CategoryResult; import { Fragment, useEffect } from "react";import { Helmet } from "react-helmet";import { useDispatch, useSelector } from "react-redux";import { Row, Spinner } from 'reactstrap';import PostCardOne from "../../components/post/PostCardOne";import { POSTS_LOADING_REQUEST } from "../../redux/types";const PostCardList = () => { const { posts } = useSelector((state) => state.post) const dispatch = useDispatch() useEffect(() => { dispatch({ type: POSTS_LOADING_REQUEST }) }, [dispatch]) return ( <Fragment> <Helmet title="Home" /> <Row> {posts ? <PostCardOne posts={posts} /> : <Spinner />} </Row> </Fragment> )}export default PostCardList; import React from 'react';const PostDetail = () => { return ( <div> PostDetail </div> )}export default PostDetail; import React from 'react';const PostEdit = () => { return ( <div> PostEdit </div> )}export default PostEdit; import React, { useState } from 'react'import { useDispatch, useSelector } from 'react-redux'import { Col, Form, FormGroup, Label, Progress, Button, Input } from 'reactstrap'import { CKEditor } from "@ckeditor/ckeditor5-react"import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor'import { editorConfiguration } from '../../components/editor/EditorConfig'import Myinit from '../../components/editor/UploadAdapter'const PostWrite = () => { const { isAuthenticated } = useSelector((state) => state.auth) const [form, setValues] = useState({ title: "", contents: "", fileUrl: "" }) const diapatch = useDispatch const onChange = (e) => { setValues({ ...form, [e.target.name]: e.target.value }) } const onSubmit = async (e) => { await e.preventDefault() const { title, contents, fileUrl, category } = form } const getDataFromCKEditor = (event, editor) => { console.log("editor") } return ( <div> {isAuthenticated ? ( <Form onSubmit={onSubmit}> <FormGroup className="mb-3"> <Label for="title">Title</Label> <Input type="text" name="title" id="title" className="form-control" onChange={onChange} /> </FormGroup> <FormGroup className="mb-3"> <Label for="category">Category</Label> <Input type="text" name="category" id="category" className="form-control" onChange={onChange} /> </FormGroup> <FormGroup className="mb-3"> <Label for="content">Content</Label> <CKEditor editor={ClassicEditor} config={editorConfiguration} onInit={Myinit} onBlur={getDataFromCKEditor} /> <Button color="success" block className="mt-3 col-md-2 offset-md-10 mb-3" > 제출하기 </Button> </FormGroup> </Form> ) : ( <Col width={50} className="p-5 m-5"> <Progress animated color="info" value={100} /> </Col> )} </div> )}export default PostWrite import React from 'react'const Profile = () => { <div> Profile </div>}export default Profile import React from 'react'const Search = () => { return ( <div> Search </div> )}export default Search

0

리엑트 블로그 만들기 12 - Loading 만들기

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 12 - Loading 만들기// USER LOADINGexport const USER_LOADING_REQUEST = "USER_LOADING_REQUEST"export const USER_LOADING_SUCCESS = "USER_LOADING_SUCCESS"export const USER_LOADING_FAILURE = "USER_LOADING_FAILURE" const authReducer = (state = initialState, action) => { switch (action.type) { case REGISTER_REQUEST: case LOGIN_REQUEST: case LOGOUT_REQUEST: return { ...state, errorMsg: "", isLoading: true } case REGISTER_SUCCESS: case LOGIN_SUCCESS: localStorage.setItem("token", action.payload.token) return { ...state, ...action.payload, isAuthenticated: true, isLoading: false, userId: action.payload.user.userId, userRole: action.payload.user.role, errorMsg: "" } case REGISTER_FAILURE: case LOGOUT_FAILURE: case LOGIN_FAILURE: localStorage.removeItem("token") return { ...state, ...action.payload, token: null, user: null, userId: null, isAuthenticated: false, isLoading: false, userRole: null, errorMsg: action.payload.user.role } case LOGOUT_SUCCESS: localStorage.removeItem("token") return { token: null, user: null, userId: null, isAuthenticated: false, isLoading: false, userRole: null, errorMsg: "" }; case CLEAR_ERROR_REQUEST: return { ...state, errorMsg: null, } case CLEAR_ERROR_SUCCESS: return { ...state, errorMsg: null, } case CLEAR_ERROR_FAILURE: return { ...state, errorMsg: null } case USER_LOADING_REQUEST: return { ...state, isLoading: true } case USER_LOADING_SUCCESS: return { ...state, isAuthenticated: true, isLoading: false, user: action.payload, userId: action.payload._id, userName: action.payload.userName, userRole: action.payload.role } case USER_LOADING_FAILURE: return { ...state, user: null, isAuthenticated: false, isLoading: false, userRole: "", } default: return state; }} // User Loadingconst userLoadingAPI = (token) => { console.log(token); const config = { headers: { "Content-Type": "applicatio n/json", }, }; if (token) { config.headers["x-auth-token"] = token; } return axios.get("api/auth/user", config);}function* userLoading(action) { try { console.log(action, "userLoading") const result = yield call(userLoadingAPI, action.payload) console.log(result) yield put({ type: USER_LOADING_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: USER_LOADING_FAILURE, payload: e.response }) }} // Clear Errorfunction* clearError() { try { yield put({ type: CLEAR_ERROR_SUCCESS, }); } catch (e) { yield put({ type: CLEAR_ERROR_FAILURE, }); }}function* watchClearError() { yield takeEvery(CLEAR_ERROR_REQUEST, clearError);} export default function* authSaga() { yield all([ fork(watchLoginUser), fork(watchLogoutUser), fork(watchUserLoading), fork(watchRegisterUser), fork(watchClearError), ]);} import { USER_LOADING_REQUEST } from '../../redux/types';import store from '../../store';const laodUser = () => { try { store.dispatch({ type: USER_LOADING_REQUEST, payload: localStorage.getItem("token"), }); } catch (e) { console.log(e); }}export default laodUser; import React from 'react';import ReactDOM from 'react-dom';import App from './App';import loadUser from './components/auth/loadUser';import './index.css';import reportWebVitals from './reportWebVitals';// 로그인을 항상 유지loadUser();ReactDOM.render( <App />, document.getElementById('root'));// If you want to start measuring performance in your app, pass a function// to log results (for example: reportWebVitals(console.log))// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitalsreportWebVitals();

0

리엑트 블로그 만들기 11 - 회원가입 리덕스 작업

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업const authReducer = (state = initialState, action) => { switch (action.type) { case REGISTER_REQUEST: case LOGIN_REQUEST: case LOGOUT_REQUEST: return { ...state, errorMsg: "", isLoading: true } case REGISTER_SUCCESS: case LOGIN_SUCCESS: localStorage.setItem("token", action.payload.token) return { ...state, ...action.payload, isAuthenticated: true, isLoading: false, userId: action.payload.user.userId, userRole: action.payload.user.role, errorMsg: "" } case REGISTER_FAILURE: case LOGOUT_FAILURE: case LOGIN_FAILURE: localStorage.removeItem("token") return { ...state, ...action.payload, token: null, user: null, userId: null, isAuthenticated: false, isLoading: false, userRole: null, errorMsg: action.payload.user.role } case LOGOUT_SUCCESS: localStorage.removeItem("token") return { token: null, user: null, userId: null, isAuthenticated: false, isLoading: false, userRole: null, errorMsg: "" }; case CLEAR_ERROR_REQUEST: return { ...state, errorMsg: null, } case CLEAR_ERROR_SUCCESS: return { ...state, errorMsg: null, } case CLEAR_ERROR_FAILURE: return { ...state, errorMsg: null } case USER_LOADING_REQUEST: return { ...state, isLoading: true } case USER_LOADING_SUCCESS: return { ...state, isAuthenticated: true, isLoading: false, user: action.payload, userId: action.payload._id, userName: action.payload.userName, userRole: action.payload.role } case USER_LOADING_FAILURE: return { ...state, user: null, isAuthenticated: false, isLoading: false, userRole: "", } default: return state; }} // Registerconst registerUserAPI = (req) => { console.log(req, "req"); return axios.post("api/user", req);};function* registerUser(action) { try { const result = yield call(registerUserAPI, action.payload); console.log(result, "RegisterUser Data"); yield put({ type: REGISTER_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: REGISTER_FAILURE, payload: e.response, }); }}function* watchRegisterUser() { yield takeEvery(REGISTER_REQUEST, registerUser);} export default function* authSaga() { yield all([ fork(watchLoginUser), fork(watchLogoutUser), fork(watchUserLoading), fork(watchRegisterUser), fork(watchClearError), ]);}

0

리엑트 블로그 만들기 10 - 회원가입 2

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 10 - 회원가입 2import React, { Fragment, useCallback, useEffect, useState } from "react";import { useDispatch, useSelector } from "react-redux";import { Link } from "react-router-dom";import { Button, Collapse, Container, Form, Nav, Navbar, NavbarToggler, NavItem,} from "reactstrap";import { LOGOUT_REQUEST } from "../redux/types";import LoginModal from "./auth/LoginModal";import RegisterModal from "./auth/RegisterModal";const AppNavbar = () => { const [isOpen, setIsOpen] = useState(false); const { isAuthenticated, user, userRole } = useSelector( (state) => state.auth ); console.log(userRole, "UserRole"); const dispatch = useDispatch(); const onLogout = useCallback(() => { dispatch({ type: LOGOUT_REQUEST, }); }, [dispatch]); useEffect(() => { setIsOpen(false); }, [user]); const handleToggle = () => { setIsOpen(!isOpen); }; const addPostClick = () => {}; const authLink = ( <Fragment> <NavItem> {userRole === "MainJuin" ? ( <Form className="col mt-2"> <Link to="posts" className="btn btn-success block text-white px-3" onClick={addPostClick} > AddPost </Link> </Form> ) : ( "" )} </NavItem> <NavItem className="d-flex justify-content-center"> <Form className="col mt-2"> {user && user.name ? ( <Link> <Button outline color="light" className="px-3" block> <strong>{user ? `Welcom ${user.name}` : ""}</strong> </Button> </Link> ) : ( <Button outline color="light" className="px-3" block> <strong>No User</strong> </Button> )} </Form> </NavItem> <NavItem> <Form className="col"> <Link onClick={onLogout} to="#"> <Button outline color="light" className="mt-2" block> Logout </Button> </Link> </Form> </NavItem> </Fragment> ); const guestLink = ( <Fragment> <NavItem> <RegisterModal /> </NavItem> <NavItem> <LoginModal /> </NavItem> </Fragment> ); return ( <div> <Navbar color="dark" dark expand="lg" className="sticky-top"> <Container> <Link to="/" className="text-white text-decoration-none"> Victor의 블로그 </Link> <NavbarToggler onClick={handleToggle} /> <Collapse isOpen={isOpen} navbar> <Nav className="ml-auto d-flex justify-content-around" navbar> {isAuthenticated ? authLink : guestLink} </Nav> </Collapse> </Container> </Navbar> </div> );};export default AppNavbar;

0

리엑트 블로그 만들기 9 - 회원가입

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 9 - 회원가입// REGISTERexport const REGISTER_REQUEST = "REGISTER_REQUEST";export const REGISTER_SUCCESS = "REGISTER_SUCCESS";export const REGISTER_FAILURE = "REGISTER_FAILURE"; import React, { useEffect, useState } from "react";import { useDispatch, useSelector } from "react-redux";import { Alert, Button, Form, FormGroup, Input, Label, Modal, ModalBody, ModalHeader, NavLink,} from "reactstrap";import { CLEAR_ERROR_REQUEST, REGISTER_REQUEST } from "../../redux/types";const RegisterModal = () => { const [modal, setModal] = useState(false); const [form, setValue] = useState({ name: "", email: "", password: "", }); const [localMsg, setLocalMsg] = useState(""); const { errorMsg } = useSelector((state) => state.auth); const dispatch = useDispatch(); const handleToggle = () => { dispatch({ type: CLEAR_ERROR_REQUEST, }); setModal(!modal); }; useEffect(() => { try { setLocalMsg(errorMsg); } catch (e) { console.error(e); } }, [errorMsg]); const onChange = (e) => { setValue({ ...form, [e.target.name]: e.target.value, }); }; const onSubmit = (e) => { e.preventDefault(); const { name, email, password } = form; const newUser = { name, email, password }; console.log(newUser, "newUser"); dispatch({ type: REGISTER_REQUEST, payload: newUser, }); }; return ( <div> <NavLink onClick={handleToggle} href="#"> Register </NavLink> <Modal isOpen={modal} toggle={handleToggle}> <ModalHeader toggle={handleToggle}>Register</ModalHeader> <ModalBody> {localMsg ? <Alert color="danger"></Alert> : null} <Form onSubmit={onSubmit}> <FormGroup> <Label for="name">Name</Label> <Input type="text" name="name" id="name" placeholder="Name" onChange={onChange} /> <Label for="email">Email</Label> <Input type="text" name="email" id="email" placeholder="email" onChange={onChange} /> <Label for="password">Password</Label> <Input type="text" name="password" id="password" placeholder="Password" onChange={onChange} /> <Button color="dark" className="mt-2" block> Register </Button> </FormGroup> </Form> </ModalBody> </Modal> </div> );};export default RegisterModal; import React, { Fragment, useCallback, useEffect, useState } from "react";import { useDispatch, useSelector } from "react-redux";import { Link } from "react-router-dom";import { Button, Collapse, Container, Form, Nav, Navbar, NavbarToggler, NavItem,} from "reactstrap";import { LOGOUT_REQUEST } from "../redux/types";import LoginModal from "./auth/LoginModal";import RegisterModal from "./auth/RegisterModal";const AppNavbar = () => { const [isOpen, setIsOpen] = useState(false); const { isAuthenticated, user, userRole } = useSelector( (state) => state.auth ); console.log(userRole, "UserRole"); const dispatch = useDispatch(); const onLogout = useCallback(() => { dispatch({ type: LOGOUT_REQUEST, }); }, [dispatch]); useEffect(() => { setIsOpen(false); }, [user]); const handleToggle = () => { setIsOpen(!isOpen); }; const addPostClick = () => {}; const authLink = ( <Fragment> <NavItem> {userRole === "MainJuin" ? ( <Form className="col mt-2"> <Link to="posts" className="btn btn-success block text-white px-3" onClick={addPostClick} > AddPost </Link> </Form> ) : ( "" )} </NavItem> <NavItem className="d-flex justify-content-center"> <Form className="col mt-2"> {user && user.name ? ( <Link> <Button outline color="light" className="px-3" block> <strong>{user ? `Welcom ${user.name}` : ""}</strong> </Button> </Link> ) : ( <Button outline color="light" className="px-3" block> <strong>No User</strong> </Button> )} </Form> </NavItem> <NavItem> <Form className="col"> <Link onClick={onLogout} to="#"> <Button outline color="light" className="mt-2" block> Logout </Button> </Link> </Form> </NavItem> </Fragment> ); const guestLink = ( <Fragment> <NavItem> <RegisterModal /> </NavItem> <NavItem> <LoginModal /> </NavItem> </Fragment> ); return ( <div> <Navbar color="dark" dark expand="lg" className="sticky-top"> <Container> <Link to="/" className="text-white text-decoration-none"> Victor의 블로그 </Link> <NavbarToggler onClick={handleToggle} /> <Collapse isOpen={isOpen} navbar> <Nav className="ml-auto d-flex justify-content-around" navbar> {isAuthenticated ? authLink : guestLink} </Nav> </Collapse> </Container> </Navbar> </div> );};export default AppNavbar;

0

리엑트 블로그 만들기 8 - 로그인 & 로그아웃

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 8 - 로그인 & 로그아웃//LOGINexport const LOGIN_REQUEST = "LOGIN_REQUEST";export const LOGIN_SUCCESS = "LOGIN_SUCCESS";export const LOGIN_FAILURE = "LOGIN_FAILURE";//LOGINexport const LOGOUT_REQUEST = "LOGOUT_REQUEST";export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS";export const LOGOUT_FAILURE = "LOGOUT_FAILURE";// CLEAR ERRORexport const CLEAR_ERROR_REQUEST = "CLEAR_REQUEST";export const CLEAR_ERROR_SUCCESS = "CLEAR_SUCCESS";export const CLEAR_ERROR_FAILURE = "CLEAR_FAILURE"; import { LOGIN_REQUEST, LOGIN_SUCCESS, LOGIN_FAILURE, CLEAR_ERROR_REQUEST, CLEAR_ERROR_SUCCESS, CLEAR_ERROR_FAILURE, LOGOUT_REQUEST, LOGOUT_SUCCESS, LOGOUT_FAILURE,} from "../types";const initialState = { token: localStorage.getItem("token"), isAuthenticated: null, isLoading: false, user: "", userId: "", userName: "", userRole: "", errorMsg: "", successMsg: "",};const authReducer = (state = initialState, action) => { switch (action.type) { case LOGOUT_REQUEST: case LOGIN_REQUEST: return { ...state, errorMsg: "", }; case LOGIN_SUCCESS: localStorage.setItem("token", action.payload.token); return { ...state, ...action.payload, isAuthenticated: true, isLoading: false, userId: action.payload.user.id, userRole: action.payload.user.role, errorMsg: "", }; case LOGOUT_FAILURE: case LOGIN_FAILURE: localStorage.removeItem("token"); return { ...state, ...action.payload, token: null, user: null, userId: null, userRole: null, errorMsg: action.payload.data.msg, }; case LOGOUT_SUCCESS: localStorage.removeItem("token"); return { ...state, ...action.payload, token: null, user: null, userId: null, isAuthenticated: false, isLoading: false, userRole: null, errorMsg: "", }; case CLEAR_ERROR_REQUEST: return { ...state, errorMsg: null, }; case CLEAR_ERROR_SUCCESS: return { ...state, errorMsg: null, }; case CLEAR_ERROR_FAILURE: return { ...state, errorMsg: null, }; default: return state; }};export default authReducer; import { all, put } from "@redux-saga/core/effects";import axios from "axios";import { call, fork, takeEvery } from "redux-saga/effects";import { LOGIN_FAILURE, LOGIN_REQUEST, LOGIN_SUCCESS, LOGOUT_REQUEST,} from "../types";const loginUserAPI = (loginData) => { console.log(loginData, "loginData"); const config = { headers: { "Content-Type": "application/json", }, }; return axios.post("api/auth", loginData, config);};function* loginUser(action) { try { const result = yield call(loginUserAPI, action.payload); console.log(result); yield put({ type: LOGIN_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: LOGIN_FAILURE, payload: e.response, }); }}function* logout(action) { try { const result = yield call(loginUserAPI, action.payload); console.log(result); yield put({ type: LOGIN_SUCCESS, }); } catch (e) { yield put({ type: LOGIN_FAILURE, }); console.log(e); }}function* watchLoginUser() { yield takeEvery(LOGIN_REQUEST, loginUser);}function* watchLogout() { yield takeEvery(LOGOUT_REQUEST, logout);}export default function* authSaga() { yield all([fork(watchLoginUser), fork(watchLogout)]);} import React, { useCallback, useEffect, useState } from "react";import { useDispatch, useSelector } from "react-redux";import { Link } from "react-router-dom";import { Collapse, Container, Nav, Navbar, NavbarToggler } from "reactstrap";import { LOGOUT_REQUEST } from "../redux/types";import LoginModal from "./auth/LoginModal";const AppNavbar = () => { const [isOpen, setIsOpen] = useState(false); const { isAuthenticated, user, userRole } = useSelector( (state) => state.auth ); console.log(userRole, "UserRole"); const dispatch = useDispatch(); const onLogout = useCallback(() => { dispatch({ type: LOGOUT_REQUEST, }); }, [dispatch]); useEffect(() => { setIsOpen(false); }, [user]); const handleToggle = () => { setIsOpen(!isOpen); }; return ( <div> <Navbar color="dark" dark expand="lg" className="sticky-top"> <Container> <Link to="/" className="text-white text-decoration-none"> Victor의 블로그 </Link> <NavbarToggler onClick={handleToggle} /> <Collapse isOpen={isOpen} navbar> <Nav className="ml-auto d-flex justify-content-around" navbar> {isAuthenticated ? ( <h1 className="text-white">authLink</h1> ) : ( <LoginModal /> )} </Nav> </Collapse> </Container> </Navbar> </div> );};export default AppNavbar;

0

리엑트 블로그 만들기 7 - Login Modal 만들기 2

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 7 - Login Modal 만들기 2import React, { useEffect, useState } from "react";import { useDispatch, useSelector } from "react-redux";import { NavLink } from "react-router-dom";import { Alert, Button, Form, FormGroup, Input, Label, Modal, ModalBody, ModalHeader,} from "reactstrap";import { CLEAR_ERROR_REQUEST, LOGIN_REQUEST } from "../../redux/types";const LoginModal = () => { const [modal, setModal] = useState(false); const [localMsg, setLocalMsg] = useState(""); const [form, setValues] = useState({ email: "", password: "", }); const dispatch = useDispatch(); const { errorMsg } = useSelector((state) => state.auth); useEffect(() => { try { setLocalMsg(errorMsg); } catch (e) { console.log(e); } }, [errorMsg]); const handleToggle = () => { dispatch({ type: CLEAR_ERROR_REQUEST, }); setModal(!modal); }; const onChange = (e) => { setValues({ ...form, [e.target.name]: e.target.value, }); }; const onSubmit = (e) => { e.preventDefault(); const { email, password } = form; const user = { email, password }; console.log(user); dispatch({ type: LOGIN_REQUEST, data: user, }); }; return ( <div> <NavLink onClick={handleToggle} href="#"> Login </NavLink> <Modal isOpen={modal} toggle={handleToggle}> <ModalHeader toggle={handleToggle}>Login</ModalHeader> <ModalBody> {localMsg ? <Alert color="danger">{localMsg}</Alert> : null} <Form> <FormGroup> <Label for="email">Email</Label> <Input type="email" name="email" id="email" placeholder="Email" onChange={onChange} /> <Label for="passowrd">Passowrd</Label> <Input type="passowrd" name="passowrd" id="passowrd" placeholder="Passowrd" onChange={onChange} /> <Button color="dark" style={{ marginTop: "2rem" }} block /> </FormGroup> </Form> </ModalBody> </Modal> </div> );};export default LoginModal;

0

리엑트 블로그 만들기 6 - Login Modal 만들기 1

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 6 - Login Modal 만들기 1import { all, put } from "@redux-saga/core/effects";import axios from "axios";import { takeEvery } from "redux-saga";import { call, fork } from "redux-saga/effects";import { LOGIN_FAILURE, LOGIN_REQUEST, LOGIN_SUCCESS } from "../types";const loginUserAPI = (loginData) => { console.log(loginData, "loginData"); const config = { headers: { "Content-Type": "application/json", }, }; return axios.post("api/auth", loginData, config);};function* loginUser(action) { try { const result = yield call(loginUserAPI, action.payload); console.log(result); yield put({ ytpe: LOGIN_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: LOGIN_FAILURE, payload: e.response, }); }}function* watchLoginUser() { yield takeEvery(LOGIN_REQUEST, loginUser);}export default function* authSaga(){ yield all([ fork(watchLoginUser) ])}

0

리엑트 블로그 만들기 5 - 리덕스 세팅하기

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 5 - 리덕스 세팅하기//LOGINexport const LOGIN_REQUEST = "LOGIN_REQUEST";export const LOGIN_SUCCESS = "LOGIN_SUCCESS";export const LOGIN_FAILURE = "LOGIN_FAILURE";// CLEAR ERRORexport const CLEAR_ERROR_REQUEST = "CLEAR_REQUEST";export const CLEAR_ERROR_SUCCESS = "CLEAR_SUCCESS";export const CLEAR_ERROR_FAILURE = "CLEAR_FAILURE"; import { LOGIN_REQUEST, LOGIN_SUCCESS, LOGIN_FAILURE, CLEAR_ERROR_REQUEST, CLEAR_ERROR_SUCCESS, CLEAR_ERROR_FAILURE,} from "../types";const initialState = { token: localStorage.getItem("token"), isAuthenticated: null, isLoading: false, user: "", userId: "", userName: "", userRole: "", errorMsg: "", successMsg: "",};const authReducer = (state = initialState, action) => { switch (action.type) { case LOGIN_REQUEST: return { ...state, errorMsg: "", }; case LOGIN_SUCCESS: localStorage.setItem("token", action.payload.token); return { ...state, ...action.payload, isAuthenticated: true, isLoading: false, userId: action.payload.user.id, userRole: action.payload.user.role, errorMsg: "", }; case LOGIN_FAILURE: localStorage.removeItem("token"); return { ...state, ...action.payload, token: null, user: null, userId: null, userRole: null, errorMsg: action.payload.data.msg, }; case CLEAR_ERROR_REQUEST: return { ...state, errorMsg: null, }; case CLEAR_ERROR_SUCCESS: return { ...state, errorMsg: null, }; case CLEAR_ERROR_FAILURE: return { ...state, errorMsg: null, }; default: return state; }};export default authReducer;

0

리엑트 블로그 만들기 4 - Navbar 작성하기

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 4 - Navbar 작성하기import React from "react";import { Link } from "react-router-dom";import { Collapse, Container, Nav, Navbar, NavbarToggler } from "reactstrap";const AppNavbar = () => { return ( <div> <Navbar color="dark" dark expand="lg" className="sticky-top"> <Container> <Link to="/" className="text-white text-decoration-none"> Victor의 블로그 </Link> <NavbarToggler /> <Collapse isOpen={true} navbar> <Nav className="ml-auto d-flex justify-content-around" navbar> {true ? ( <h1 className="text-white">authLink</h1> ) : ( <h1 className="text-white">gestLink</h1> )} </Nav> </Collapse> </Container> </Navbar> </div> );};export default AppNavbar; import React, { Fragment } from "react";import Header from "../components/Header";import Footer from "../components/Footer";import AppNavbar from "../components/AppNavbar";const MyRouter = () => ( <Fragment> <AppNavbar /> <Header> <h1>Hello Body</h1> </Header> <Footer></Footer> </Fragment>);export default MyRouter;

0

리엑트 블로그 만들기 3 - Header 작성하기

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 3 - Header 작성하기import React from "react";import { Row, Col } from "reactstrap";const Header = () => { return ( <div id="page-header"> <Row> <Col md="6" sm="auto" className="text-center m-auto"> <h1>Read Our Blog</h1> <p>Victor의 사이드 블로그 입니다.</p> </Col> </Row> </div> );};export default Header; #main-footer{ background: #343a40; color:#fff;}#page-header{ height:200px; background: url(./img/free-image.jpeg); background-position: 54% 94%; background-attachment: fixed; color: #fff; border-bottom: 1px #eee solid; padding-top: 60px;}

0

리엑트 블로그 만들기 2 - Footer 작성하기

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 2 - Footer 작성하기import React from "react";import { Row, Col } from "reactstrap";const Footer = () => { const thisYear = () => { const year = new Date().getFullYear(); return year; }; return ( <div id="main-footer" className="text-center m-center p-2"> <Row> <Col> <p> Copyright Copy <span>{thisYear()}</span> </p> </Col> </Row> </div> );};export default Footer; 패키지 설치 npm install node-sass sass-loaderyarn add node-sass sass-loader #main-footer{ background: #343a40; color:#fff;} import React from "react"import { Provider } from 'react-redux'import { ConnectedRouter } from 'connected-react-router'import store, { history } from "./store"import MyRouter from './routes/Router'import "bootstrap/dist/css/bootstrap.min.css";import "./assets/custom.scss"const App = () => { return ( <Provider store={store}> <ConnectedRouter history={history}> <MyRouter /> </ConnectedRouter> </Provider> );}export default App;

0

리엑트 블로그 만들기 1 - 초기 setting 하기

리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 1 - 초기 setting 하기yarn add axios redux react-redux redux-saga react-router-dom connected-react-router dotenv bootstrap reactstrap Root Reducer 생성/src/redux/reducers/index.js import { connectRouter } from 'connected-react-router';import { combineReducers } from "redux";// Root Reducer를 생성한다.const createRootReducer = (history) => combineReducers({ router: connectRouter(history),});export default createRootReducer; Root Saga 생성/src/redux/sagas/index.js import { all } from 'redux-saga/effects';// Root Saga를 생성한다.export default function* rootSaga() { yield all([]);}