프로그램 6주차 2022/04/10~ 2022/04/17 미니프로젝트 

 

과제 요구사항 

 

 

구현된 페이지와 기능들

 

 

라우터 시켜주는곳 App.js

내 코드

더보기
import React from "react";
import { BrowserRouter, Route } from "react-router-dom";
import { Switch } from "react-router-dom";
import Header from "./components/Header";
import PostList from "./pages/PostList";
import Login from "./pages/Login";
import Signup from "./pages/Signup";
import PostDetail from "./pages/PostDetail";
import PostAdd from "./pages/PostAdd";
import PostModify from "./pages/PostModify";
import { history } from "./redux/configureStore";
import { ConnectedRouter } from "connected-react-router";
function App() {
return (
<React.Fragment>
<Header></Header>
<ConnectedRouter history={history}>
<Route path="/" exact component={PostList} />
<Route path="/login" exact component={Login} />
<Route path="/signup" exact component={Signup} />
<Route path="/detail/:id" exact component={PostDetail} />
<Route path="/add" exact component={PostAdd} />
<Route path="/modify/:id" exact component={PostModify} />
</ConnectedRouter>
</React.Fragment>
);
}

 

export default App;

 

 

내 리듀서와 연결해주는 configStore.js

내 코드

더보기
import { createStore, combineReducers, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import { createBrowserHistory } from "history";
import { connectRouter } from "connected-react-router";

 

import User from "./modules/user";
import Post from "./modules/post";
import image from "./modules/image";

 

export const history = createBrowserHistory();
// 위의 정보와 밑의정보로 히스토리로 라우터와 연결되어 스토에어 저장됨
const rootReducer = combineReducers({
user: User,
post: Post,
image: image,
router: connectRouter(history),
});

 

const middlewares = [thunk.withExtraArgument({ history: history })];
//withExtraArgument 다른인수를 넘겨주는 청크의 내장함수

 

// 지금이 어느 환경인 지 알려줘요. (개발환경, 프로덕션(배포)환경 ...)
//pocess.env.NODE_ENV 사용시 개발활경이 어느거인지 찍어줌
// 빌드해서 나온 파일에 적용시 production 이라고 찍힘
const env = process.env.NODE_ENV;

 

// 개발환경에서는 로거라는 걸 하나만 더 써볼게요.

 

if (env === "development") {
const { logger } = require("redux-logger");
middlewares.push(logger);
}
/*

 

development = 개발환경
require 을 쓰는이유 : 패키지를 가져올때
import로 안쓰고 require 를 쓰는이유
로거는 콘솔에 찍히는거임
콘솔에 이전상태 이후상태가 찍힘
리덕스안에 스토어가있는데 그 데이터에 뭐가담기는지
어떤액션이 일어나서 이전에 뭐였는지 뭐로 변했는지 찍힘
사용자에겐 보여질필요는없으니 개발환경일때에만 보이게해줌
빌드한 프로덕션에서 import할필요가없어짐
모돌의 사이즈만 커지고 프로젝트 사이즈만 커지는상황이 발생해서 import로 사용하지않음
if문을 주어 require로 써서 사용함

 

*/

 

const composeEnhancers =
typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
})
: compose;
const enhancer = composeEnhancers(applyMiddleware(...middlewares)); //미들웨어를 묶어주는 곳
let store = (initialStore) => createStore(rootReducer, enhancer);

 

export default store();
/*

 

자바스크립트는 V8 엔진이 돌아가기만 하면 브라우저가 아니여도 돌아감
근데 브라우저가 아닐때면 윈도우라는 객체가 없음
그래서 브라우저일때만 돌려주려고
typeof window === "object"

 

요게들어있음

 

window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__

 

윈도우에 리덕스데브툴즈가 깔려있냐는 물어보는곳

 

윈도우 상태가 객체이고 리덕스 데브툴즈가 깔려있다면 실행하라는구문

 

*/

 

 

적용된 리듀서와 CURD 가 있는 post.js

내코드

 

더보기
import axios from "axios";
import { produce } from "immer";
import { createAction, handleActions } from "redux-actions";
import "moment";
import moment from "moment";
import api from "../../api/api";
//로드
const LOAD = "post/LOAD";

 

const ADD = "post/ADD";

 

const EDIT = "post/EDIT";

 

const DELETE = "post/DELETE";

 

const LOADING = "LOADING";

 

//액션 크리에이터

 

const loadPost = createAction(LOAD, (postObject) => ({ postObject }));

 

const addPost = createAction(ADD, (post) => ({ post }));

 

const editPost = createAction(EDIT, (post_id, post) => ({
post_id,
post,
}));
const deletePost = createAction(DELETE, (post_id) => ({ post_id }));

 

const initialState = {
uploading: false,
preview: null,
title: "",
contents: "",
post: [],
paging: { start: null, next: null, size: 3 },
is_loading: false,
};
// middlewares

 

const loadPostDB = () => {
return async function (dispatch, getState, { history }) {
await api
.get("api/posts")
.then((res) => {
console.log(12345);

 

dispatch(loadPost(res.data));
})
.catch((err) => {
console.log(err);
});
};
};

 

const addPostDB = (post) => {
console.log(post);
const token = sessionStorage.getItem("token");

 

return async function (dispatch, getState, { history }) {
console.log(token);
const form = new FormData();
form.append("file", post.image);
form.append(
"postsRequestDto",
new Blob([JSON.stringify({ contents: post.contents })], {
type: "application/json",
})
);

 

console.log("글 추가 시도");
await api
.post("/api/posts/write", form, {
headers: {
Accept: "*/*",
"Content-Type": `multipart/form-data`,
Authorization: `${token}`,
},
})
.then(function (res) {
console.log(res);
dispatch(loadPostDB());
history.replace("/");
console.log("글 추가 성공!!", res);
})
.catch((err) => {
console.log("글 추가 실패!", err);
});
};
};

 

const editPostDB = (post_id, post) => {
return async function (dispatch, getState, { history }) {
const form = new FormData();
form.append("file", post.image);
form.append(
"postsRequestDto",
new Blob([JSON.stringify({ contents: post.contents })], {
type: "application/json",
})
);

 

await api
.put(`/api/posts/modify/${post_id}`, form, {
headers: {
Accept: "*/*",
"Content-Type": `multipart/form-data`,
},
})
.then((response) => {
dispatch(editPost(post_id, { ...form }));
dispatch(loadPostDB());
history.replace("/");
})
.catch((err) => {
window.alert("수정 실패");
});
};
};

 

const deletePostDB = (post_id = null) => {
return async function (dispatch, getState, { history }) {
await api
.delete(`/api/posts/delete/${post_id}`, { post_id })
.then((doc) => {
dispatch(deletePost(post_id));
dispatch(loadPostDB());
history.replace("/");
})
.catch((error) => {
window.alert("아 게시물 삭제에 문제가 있어요");
console.log("앗! 게시물 삭제에 문제가있어요!", error);
});
};
};
export default handleActions(
{
[LOAD]: (state, action) =>
produce(state, (draft) => {
console.log(1234455555);
draft.post = action.payload.postObject;
draft.is_loading = false;
}),
[ADD]: (state, action) =>
produce(state, (draft) => {
draft.post = action.payload.post;
}),
[EDIT]: (state, action) =>
produce(state, (draft) => {
let idx = draft.post.findIndex((p) => {
return p.id + "" === action.payload.post_id;
}); //p.id + "" === action.payload.post_id

 

draft.post[idx] = { ...draft.post[idx], ...action.payload.post };
}),
[DELETE]: (state, action) =>
produce(state, (draft) => {
draft.post = draft.post.filter((a) => a.id !== action.payload.post_id);
}),
[LOADING]: (state, action) =>
produce(state, (draft) => {
draft.is_loading = action.payload.is_loading;
}),
},
initialState
);

 

const actionCreators = {
loadPostDB,
addPostDB,
editPostDB,
deletePostDB,
};

 

export { actionCreators };

 

 

적용된 리듀서와 CURD 가 있는 user.js

내 코드

더보기
import { createAction, handleActions } from "redux-actions";
import { produce } from "immer";
//import axios from 'axios'
import api from "../../api/api";
import Cookies from "universal-cookie";
import jwt_decode from "jwt-decode";

 

import { setToken } from "../../shared/token";
import { setCookie, deleteCookie } from "../../shared/Cookie";

 

const cookies = new Cookies();

 

// actions
const LOG_OUT = "LOG_OUT";
const GET_USER = "GET_USER";
const SET_USER = "SET_USER";

 

// action creators
const setUser = createAction(SET_USER, (user) => ({ user }));
const getUser = createAction(GET_USER, () => ({}));
const logOut = createAction(LOG_OUT, () => ({}));

 

// initialState
const initialState = {
userInfo: {
userId: "",
username: "",
},
isLogin: false,
};

 

// const loginCheckDB = () => {
// const token = sessionStorage.getItem("token");
// return async function (dispatch, getState, { history }) {
// await api
// .post(
// "/auth",
// {},
// {
// headers: {
// "content-type": "applicaton/json;charset=UTF-8",
// accept: "application/json",
// Authorization: `${token}`,
// },
// }
// )
// .then((res) => {
// dispatch(
// setUser({
// userId: res.data.userId,
// username: res.data.username,
// })
// );
// })
// .catch((err) => {
// console.log("로그인 확인 실패", err);
// });
// };
// };

 

const loginDB = (userId, password) => {
return function (dispatch, getState, { history }) {
const token = sessionStorage.getItem("token");
api
.post(
"/api/user/login",
{
userId: userId,
password: password,
}
// {
// headers: {
// "content-type": "applicaton/json;charset=UTF-8",
// accept: "application/json",
// Authorization: `${token}`,
// },
// }
)
// .then((res) => {
// console.log(res);
// const token_res = res.data.token;
// setToken(token_res);
// return res.data;
// })
// .then((token_res) =>{
// api({
// method: "get",
// url: "/auth",
// headers: {
// "Authorization": `Bearer ${token_res}`,
// },
// })
.then((res) => {
console.log(res.data);
dispatch(
setUser({
userId: res.data.userId,
username: res.data.username,
})
);

 

const accessToken = res.data.token;
console.log(accessToken);
// cookies.set("myJWT", accessToken, { path: "/" });
const { username } = jwt_decode(accessToken);
console.log(username);
// cookies.set("userId", USER_ID, { path: "/" });
cookies.set("userName", username, { path: "/" });

 

cookies.set("isLogin", username, `${accessToken}`);

 

window.alert("로그인 완료");
history.replace("/");
window.location.reload();

 

})
.catch((err) => {
console.log(err);
});

 

// .catch((err) => {
// console.log("로그인 확인 실패", err)
// })
// history.replace('/')
//})
// .catch((err) => {
// window.alert("이메일이나 패스워드를 다시 확인해주세요!")
// })
};
};

 

const signUpDB = (userId, password, username, gender) => {
return async function (dispatch, getState, { history }) {
await api

 

.post("/api/user/signup", {
userId: userId,
username: username,
password: password,
gender: gender,
})
.then((res) => {
console.log(res);
window.alert("회원가입이 완료되었습니다!");
history.replace("/");
})
.catch((err) => {
window.alert("이미 존재하는 아이디입니다!");
});
// .catch((err) => {
// window.alert(err.response.data.errorMessage);
// })
};
};

 

const logoutDB = () => {
return function (dispatch, getState) {
cookies.remove("isLogin");
cookies.remove("userName");
};
};

 

export default handleActions(
{
[SET_USER]: (state, action) =>
produce(state, (draft) => {
setCookie("isLogin", "success");

 

draft.userInfo = action.payload.user;
console.log(1111, draft, draft.userInfo);
draft.isLogin = true;
console.log(draft.isLogin);
}),
[LOG_OUT]: (state, action) =>
produce(state, (draft) => {
deleteCookie("isLogin");
deleteCookie("userName");
draft.userInfo = {
userId: "",
username: "",
};
draft.isLogin = false;
}),

 

[GET_USER]: (state, action) => produce(state, (draft) => {}),
},
initialState
);

 

// action creator export
const actionCreators = {
logOut,
logoutDB,
getUser,
signUpDB,
loginDB,
// loginCheckDB,
};

 

export { actionCreators };

 

적용된 리듀서와 CURD 가 있는 image.js

내 코드

 

더보기
import { createAction, handleActions } from "redux-actions";
import produce from "immer";
import axios from "axios";
import api from "../../api/api";

 

const UPLOADING = "UPLOADING";
const UPLOAD_IMAGE = "UPLOAD_IMAGE";
const SET_PREVIEW = "SET_PREVIEW";

 

const uploading = createAction(UPLOADING, (uploading) => ({ uploading }));
const uploadImage = createAction(UPLOAD_IMAGE, (imageURl) => ({ imageURl }));
const setpreview = createAction(SET_PREVIEW, (preview) => ({ preview }));

 

const initialState = {
imageURl:
uploading: false,
preview: null,
};

 

const uploadImageFB = (imageForm) => {
console.log(uploadImageFB);
return function (dispatch, getState, { history }) {
dispatch(uploading(true));
api
.post("/api/posts/write", imageForm)
.then(function (res) {
console.log("upload response !! ", res);

 

dispatch(uploadImage(`http://3.35.27.159:8080/${res.data}`));
})
.catch(function (error) {
console.log(error);
});
};
};

 

export default handleActions(
{
[UPLOAD_IMAGE]: (state, action) =>
produce(state, (draft) => {
draft.imageURl = action.payload.imageURl;
draft.uploading = false;
}),

 

[UPLOADING]: (state, action) =>
produce(state, (draft) => {
draft.uploading = action.payload.uploading;
}),

 

[SET_PREVIEW]: (state, action) =>
produce(state, (draft) => {
draft.preview = action.payload.preview;
}),
},
initialState
);

 

const actionCreators = {
uploadImage,
uploadImageFB,
setpreview,
uploading,
};

 

export { actionCreators };

 

 

db와 연결되어있는 모든 데이터를 불러오는  메인페이지 PostList.js

 

내코드

더보기
import React, { useEffect } from "react";
import axios from "axios";
import { __loadPost } from "../redux/modules/post";
import { useDispatch, useSelector } from "react-redux";
import { useHistory } from "react-router-dom/cjs/react-router-dom.min";
import { actionCreators as postActions } from "../redux/modules/post";
import styled from "styled-components";
import { Grid, Button, Input, Text } from "../elements";
import Post from "../components/Post";
import { history } from "../redux/configureStore";
import {IoIosAddCircle} from "react-icons/io";

 

const PostList = (props) => {
const dispatch = useDispatch();
const post = useSelector(({ post }) => post.post);
const posit = useSelector((props) => props);
console.log(posit);

 

console.log(post);

 

useEffect(() => {
if (post.length === 0) {
dispatch(postActions.loadPostDB());
}
}, []);

 

return (
<React.Fragment>
<Grid margin="10px">
{post.map((p, idx) => {
return (
<Grid>
<Post {...p} />
</Grid>
);
})}
</Grid>
 
<IoIosAddCircle size="80" color="#262a2a"
 
onClick={(event) => {
history.push(`/add`);
event.stopPropagation();
}}/>
 
 
</React.Fragment>
);
};

 

export default PostList;

 

 

db 저장되어있는 회원 정보를 비교하여 해당 아이디로 접속하게 도와주는  로그인페이지  Login.js

 

내 코드

더보기
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import styled from "styled-components";
import '../App.css'

 

import UserInput from "../components/UserInput";
import { Text, Button, Grid, Image } from "../elements";
import { actionCreators as userActions } from "../redux/modules/user";
import { idCheck } from "../shared/common";
import PostList from "./PostList";

 

const Login = (props) => {
const { history } = props;
const dispatch = useDispatch();

 

const [userId, setUserId] = useState("");
const [password, setPassword] = useState("");

 

const login = () => {
if (userId === "" || password === "") {
window.alert("아이디와 비밀번호를 입력해주세요!");
return;
}

 

if (!idCheck(userId)) {
window.alert("아이디 형식이 맞지 않습니다!");
return;
}

 

dispatch(userActions.loginDB(userId, password));
};

 

return (
<LoginWrap>
 

 

<Text margin="0px 00px 48px 0px" size="35px" bold>
로그인
</Text>
<ContentWrap>
<Text margin="0px 0px 8px 0px">아이디</Text>
<UserInput
_onChange={(e) => {
setUserId(e.target.value);
}}
placeholder="아이디를 입력해주세요!"
margin="0px 0px 36px 0px"
value={userId}
/>
<Text margin="0px 0px 8px 0px">패스워드</Text>
<UserInput
_onChange={(e) => {
setPassword(e.target.value);
}}
placeholder="패스워드를 입력해주세요!"
margin="0px 0px 36px 0px"
value={password}
type="password"
/>
</ContentWrap>
<ButtonWrap>
<Btn width="48%" onClick={login}>
로그인
</Btn>
<Btn
width="48%"
onClick={() => {
history.push("/signup");
}}
>
회원가입
</Btn>
</ButtonWrap>
</LoginWrap>
);
};

 

const LoginWrap = styled.div`
width: calc(90% - 400px);
padding: 80px 40px;
margin: 0 auto;
text-align: center;
`;
const ContentWrap = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
`;

 

const ButtonWrap = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
`;

 

const Logo = styled.img`
height: 50%;
width: 50%;
margin: 100px;
`;

 

const Btn = styled.button`
height: 50px;
width:95%;
background-color: #9fcfcf;
margin: auto;
border: none;
border-radius: 30px;
font-family: "Noto Sans KR", sans-serif;
font-size: 1rem;
color:#ffffff;
font-weight: 1000;
text-align: center;
text-decoration: none;
margin: 15px;
`;

 

export default Login;

 

 

신규사용자가 회원가입하여  회원정보를 db로 넘겨주는  회원가입페이지 :  Signup.js

내 코드

더보기
import React, { useDebugValue, useState } from "react";
import { useDispatch } from "react-redux";
import styled from "styled-components";
import UserInput from "../components/UserInput";
//import axios from 'axios';

 

import { Text, Button,Grid, Image } from "../elements";
import { actionCreators as userActions } from "../redux/modules/user";
import { idCheck, usernameCheck } from "../shared/common";

 

const Signup = (props) => {
const { history } = props;
const dispatch = useDispatch();

 

const [userId, setUserId] = useState("");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [pwd_check, setPwdCheck] = useState("");
const [gender, setGender] = useState("");

 

const signup = () => {
if (
userId === "" ||
password === "" ||
username === "" ||
pwd_check === "" ||
gender === ""
) {
window.alert("모두 입력해주세요!");
return;
}

 

if (!idCheck(userId)) {
window.alert("아이디 형식이 맞지 않습니다!");
return;
}

 

if (!usernameCheck(username)) {
window.alert("닉네임에는 기호가 없어야 합니다!");
return;
}

 

if (password !== pwd_check) {
window.alert("패스워드와 패스워드 확인이 일치하지 않습니다!");
return;
}

 

dispatch(userActions.signUpDB(userId, password, username, gender));
};

 

return (
<SignupWrap>
 

 

<Text margin="0px 0px 48px 0px" size="35px" bold>
회원가입
</Text>
<ContentWrap>
<Text margin="0px 0px 8px 0px">아이디</Text>
<UserInput
_onChange={(e) => {
setUserId(e.target.value);
}}
placeholder="아이디를 입력해주세요!"
margin="0px 0px 24px 0px"
value={userId}
/>
{/* <button>중복확인</button> */}
<Text margin="0px 0px 8px 0px">닉네임</Text>
<UserInput
_onChange={(e) => {
setUsername(e.target.value);
}}
placeholder="닉네임을 입력해주세요!"
margin="0px 0px 24px 0px"
value={username}
/>
{/* <button>중복확인</button> */}

 

<Text margin="0px 0px 8px 0px">패스워드</Text>
<UserInput
_onChange={(e) => {
setPassword(e.target.value);
}}
placeholder="패스워드를 입력해주세요!"
margin="0px 0px 24px 0px"
value={password}
type="password"
/>

 

<Text margin="0px 0px 8px 0px">패스워드 확인</Text>
<UserInput
_onChange={(e) => {
setPwdCheck(e.target.value);
}}
placeholder="패스워드를 똑같이 입력해주세요!"
margin="0px 0px 24px 0px"
value={pwd_check}
type="password"
/>

 

<Text margin="0px 0px 8px 0px">성별</Text>
<UserInput
_onChange={(e) => {
setGender(e.target.value);
}}
placeholder="여자 혹은 남자로 입력해주세요!"
margin="0px 0px 24px 0px"
value={gender}
/>
</ContentWrap>
<ButtonWrap>
<Btn width="48%" _onClick={signup}>
회원가입
</Btn>
<Btn
width="48%"
_onClick={() => {
history.push("/login");
}}
>
로그인
</Btn>
</ButtonWrap>
</SignupWrap>
);
};

 

const SignupWrap = styled.div`
width: calc(90% - 400px);
padding: 80px 40px;
margin: 0 auto;
text-align: center;
`;

 

const ContentWrap = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
`;

 

const ButtonWrap = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
`;

 

const Btn = styled.button`
height: 50px;
width:95%;
background-color: #9fcfcf;
margin: auto;
border: none;
border-radius: 30px;
font-family: "Noto Sans KR", sans-serif;
font-size: 1rem;
color:#ffffff;
font-weight: 1000;
text-align: center;
text-decoration: none;
margin: 15px;
`;

 

// const Logo = styled.img`
// height: 50%;
// width: 50%;
// margin: 100px;
// `;
export default Signup;

 

db에  정보를 저장하는   PostAdd.js

내 코드

 

더보기
import React, { useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import { actionCreators as postActions } from "../redux/modules/post";
import { Grid, Button, Input, Text } from "../elements";
import { history } from "../redux/configureStore";
import Upload from "../shared/Upload";
import Cookies from "universal-cookie";

 

const cookies = new Cookies();
const PostAdd = (props) => {
const dispatch = useDispatch();
const fileInput = useRef();
const [contents, setContents] = React.useState("");

 

const cookies = new Cookies();

 

const is_login = cookies.get("is_login");
const userName = cookies.get("userName");

 

const preview = useSelector((state) => state.image.preview);
const changeContents = (e) => {
setContents(e.target.value);
};

 

const addPostBtn = () => {
let image = fileInput.current.files[0];
console.log(image);

 

dispatch(postActions.addPostDB({ contents: contents, image: image }));
};
if (!is_login && !userName) {
return (
<Grid margin="100px 0px" padding="16px" center>
<Text size="32px" bold>
앗! 잠깐!
</Text>
<Text size="16px">로그인 후에만 글을 쓸 수 있어요!</Text>
<Button
_onClick={() => {
history.replace("/");
}}
>
로그인 하러가기
</Button>
</Grid>
);
} else {
return (
<React.Fragment>
<Grid padding="16px">
<Text margin="0px 0px 10px 10px">
jpg, jpeg, png, gif 업로드 가능
</Text>
<Upload preview={preview} _ref={fileInput} />
</Grid>
<Grid>
<Grid padding="16px">
<Text margin="0px" size="36px" bold>
게시글 작성
</Text>
</Grid>
</Grid>

 

<Grid>
<Grid padding="16px">
<Text margin="0px" size="24px" bold>
미리보기
</Text>
</Grid>
</Grid>

 

<Grid padding="16px">
<Input
value={contents}
_onChange={changeContents}
label="게시글 내용"
placeholder="게시글 작성"
multiLine
/>
</Grid>

 

<Grid padding="16px">
<Button text="게시글 작성" _onClick={addPostBtn}></Button>)
</Grid>
</React.Fragment>
);
}
};

 

export default PostAdd;

 

db에 저장한 정보를 불러와 정보를 수정 및 삭제하는   PostModify.js

내 코드

 

더보기
import React, { useEffect, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import { actionCreators as postActions } from "../redux/modules/post";
import { Grid, Button, Input, Text } from "../elements";
import axios from "axios";
import Post from "../components/Post";
import api from "../api/api";
import Upload from "../shared/Upload";
import styled from "styled-components";
import { history } from "../redux/configureStore";
import Cookies from "universal-cookie";

 

const PostWrite = (props) => {
const post_id = props.match.params.id;
const dispatch = useDispatch();
const fileInput = useRef();
const post_list = useSelector((state) => state.post.post);

 

const preview = useSelector((state) => state.image.preview);

 

const cookies = new Cookies();

 

const is_login = cookies.get("is_login");
const userName = cookies.get("userName");

 

const [post, setPost] = React.useState({
userId: "",
username: "",
password: "",
contents: "",
modifiedAt: "",
imgUrl: "",
userIcon: "",
comment: "",
date: "",
});
const changeContents = (e) => {
setPost({
// ...post,
contents: e.target.value,
});
};

 

useEffect(() => {
setPost(
api
.get(`/api/posts/` + post_id)
.then((response) => {
setPost({
imgUrl: response.data.imgUrl,
contents: response.data.contents,
});
})
.catch((err) => {
console.log(err);
})
);
}, []);

 

const editPost = () => {
let image = fileInput.current.files[0];
dispatch(
postActions.editPostDB(post_id, {
contents: post.contents,
image: image,
})
);
};

 

const deletePost = () => {
dispatch(postActions.deletePostDB(post_id));
};

 

if (!is_login && !userName) {
return (
<Grid margin="100px 0px" padding="16px" center>
<Text size="32px" bold>
앗! 잠깐!
</Text>
<Text size="16px">로그인 후에만 수정 및 삭제가 가능합니다!</Text>
<Button
_onClick={() => {
history.replace("/");
}}
>
로그인 하러가기
</Button>
</Grid>
);
} else {
return (
<React.Fragment>
<Box>
<Grid>
<Grid padding="16px">
<Text margin="0px" size="36px" bold>
{post.userId}님 게시글 수정
</Text>
</Grid>
</Grid>

 

<Grid>
<Grid padding="16px">
<Text margin="0px" size="24px" bold>
미리보기
</Text>
</Grid>
</Grid>
<Grid padding="16px">
<Text margin="0px 0px 10px 10px">
jpg, jpeg, png, gif 업로드 가능
</Text>
<Upload preview={preview} _ref={fileInput} />
{/* https://wpi.digication.com/srvs/filemanager/campus/jDt5abnGTNWMW3zpvKz5/resize=fit:crop,align:center,width:1182,height:667/compress/cache?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnQiOiJjYW1wdXMiLCJrZXkiOiJqRHQ1YWJuR1ROV01XM3pwdkt6NSIsImV4cCI6OTk5OTk5OTk5OX0.UJ6s9UfmkeztKB_VajDR7LD1aOvLSrtPLz-gfi5I2_M"}> */}
</Grid>
<Grid padding="16px">
<Input
value={post.contents}
_onChange={changeContents}
label="게시글 내용"
placeholder="게시글 작성"
multiLine
/>
</Grid>
<Grid padding="16px">
<Btn onClick={editPost}>게시글 수정</Btn>
<Btn margin="30px" onClick={deletePost}>
게시글 삭제
</Btn>
</Grid>
</Box>
</React.Fragment>
);
}
};

 

const Box = styled.div`
//height: auto;
width: 70%;
margin: auto auto 500px auto;
margin-top: 200px;
display: block;
background-color: #d8e8e8;
border: 1px solid mome;
border-radius: 30px;
box-shadow: 20px 5px 30px #d7dbd9;
`;

 

const Btn = styled.button`
height: 50px;
width: 95%;
background-color: #ffffff;
margin: auto;
border: none;
border-radius: 30px;
font-family: "Noto Sans KR", sans-serif;
font-size: 1rem;
color: #065555;
font-weight: 1000;
text-align: center;
text-decoration: none;
margin: 15px;
`;

 

export default PostWrite;

 

 

나의 생각

 

지난 주차에 배운 리덕스를 활용하여 미니 팀프로젝트를 하는 주차였습니다.

큰 틀로 나뉘어 작업해보는 한주였고 axios 방식으로 정보를 주고받는 방법에대해 새롭게 배워보는 한주였습니다

파이어베이스를 사용하여 데이터베이스에 저장하고 수정하던 저번주와 다르게 백엔드분들의 데이터베이스에 처음 연결해보는 한주였습니다

CRUD 기능을 위해 기술매니저 님들에게 설명받은 임시 db도 사용해볼수있는 배워가는게 많은 한주였습니다

 

이 기간중 배운것

1. 백엔드분들이 정한 api와 내가 보내는 api가 같아야 연결이 되는점

2. Form 데이터를 활용하여 db에 이미지를 보내는법

3. db가 없을시에 CRUD를 미리 확인해볼수있는 임시 DB json server

4. aixos 로 정보를 주고 받을수있는 방식

5. 로그인 시 토큰을 받아 쿠키에 저장하여 사용할수있는 방법

 

앞으로의 필요한 점

 

1. 다른 방식의 코드를 내 코드에 적용하는 방법

2. 자바스크립트 함수 사용법

3. 코드를 간결하게 줄이는법

4. redux 활용법

5. axios 로 db에 연결하여 CRUD를 작성하는법

6. 리애트 훅 사용법

7. 로그인 관련 작동방식

8. 발표력 향상

9. 이미지 올리는법과 Form 데이터 사용법

 

2022/04/15~ 2022/04/17  ( 클론코딩  )

 

https://github.com/insidelamp/react_mini

 

GitHub - insidelamp/react_mini

Contribute to insidelamp/react_mini development by creating an account on GitHub.

github.com

 

 

2022/04/17~ 2022/04/17 ( 5주 차 회고 ) 

항해를 시작하고 5주차가 지나고 작성하는 회고입니다

항해 기간중 배웠던 기능들을 반복해서 사용하여 적응하고 새로 기능들을 배워 적용해야 하는 한주였습니다

새로운 방법을 터득해 적용하고 사용해야하는 한주였고 부족함을 많이 느끼고있어 더욱 공부를 해야할것같습니다

현재에 안주하지말고 더욱더 노력해보겠습니다

 

What I Learned

이번 WIL 키워드

  • 프론트엔드, 백엔드로서 첫 협업을 진행하며 느낀 아쉬운 점, 뿌듯한 점

첫 협업을 진행하며 느낀 아쉬운 점

  • 아직 프론트엔드에 대한 지식이 많지않아 자신감있게 예기를 못한점이 아쉽습니다
  • 기능구현이 얼마나 걸리는지에 대해 정보가 적어 벡엔드 분들이 추가하자는 기능들에대해 반대의견을 내고 필수로 적용하는 기능들에대해서도 완벽히 구현을 하지 못하였습니다
  • 깃허브 나 인터넷의 도움을 받아 진행하는것이 대부분이였고 기능들을 만들어봤지만 완벽히 이해를 못하고 있습니다
  • 작성된 기능이나 깃허브 내용을 가져온 기능들에대해 왜 사용하는지에 대한 것을 자세히 모르는점

 

첫 협업을 진행하며 느낀 뿌듯한 점

  • 임시로 서버를 열어 CRUD 기능을 사용해볼수있다는점
  • 정해진 api 대로 따라가야 db와 연결할수있다는 것을 배운점
  • 주특기 주차에서는 동영상을 따라해야 작성이 가능했지만 부족한 부분을 찾아서 작성할수있고 문제인 부분을 콘솔로 찍어 확인할수 있는 점

 

 

 

 

 

 

 

 

'프로그램 시작후 각 주차 정리' 카테고리의 다른 글

프로그램 8주차  (0) 2022.05.01
프로그램 7주차  (0) 2022.04.24
프로그램 5주차  (0) 2022.04.10
프로그램 4주차  (0) 2022.04.03
프로그램 3주차  (0) 2022.03.27

+ Recent posts