- 어제에 이어서 게시글 목록 페이지를 만들도록 하겠다.
- 헤더, 포스트 리스트, 페이지 컴포넌트를 만들도록 하겠다.
1. 헤더
- C:\data\react\blog\client\src\components\(new)Header.js
import React from 'react';
import { Link } from 'react-router-dom';
import '../css/Header.css';
const Header = () => {
return (
<div className="headerBlock">
<div className="logo">
<Link to="/">REACTERS</Link>
</div>
<div className="right">
<button className="grayButton">로그아웃</button>
</div>
</div>
);
};
export default Header;
- C:\data\react\blog\client\src\css\(new)Header.css
.headerBlock {
background: yellow;
overflow: hidden;
width: 100%;
background: white;
box-shadow: 5px 5px 5px gray;
padding: 1rem;
}
.logo {
float: left;
font-size: 1.125rem;
font-weight: 800;
letter-spacing: 2px;
}
.right {
margin-right: 1rem;
float: right;
}
.right .userinfo {
margin-right: 1rem;
font-weight: 800;
}
1-1. 포스트 리스트
- C:\data\react\blog\client\src\components\PostList.js
import React from 'react';
const PostList = () => {
return (
<div>
</div>
);
};
export default PostList;
1-2. 헤더와 포스트 리스트를 담을 페이지 생성
- C:\data\react\blog\client\src\pages\PostListPage.js
import React from 'react';
import Header from '../components/Header';
import PostList from '../components/PostList';
const PostListPage = () => {
return (
<div>
<Header/>
<PostList/>
</div>
);
};
export default PostListPage;
1-3. App에 포스트리스트페이지를 Route 하겠다.
- C:\data\react\blog\client\src\App.js
import './App.css';
import { Route } from 'react-router-dom'
import LoginPage from './pages/LoginPage';
import RegisterPage from './pages/RegisterPage';
import PostListPage from './pages/PostListPage';
function App() {
return (
<div className="App">
<Route path="/" component={PostListPage}/>
<Route path="/login" component={LoginPage}/>
<Route path="/register" component={RegisterPage}/>
</div>
);
}
export default App;
- C:\data\react\blog\client\src\App.css
.App {
width: 1024px;
margin: 0 auto;
}
@media screen and (max-width: 1024px) {
.App {
width: 768px;
}
}
@media screen and (max-width: 768px) {
.App {
width: 100%;
}
}
.grayButton {
border: none;
border-radius: 4px;
font-size: 0.9rem;
font-weight: bold;
padding: 0.4rem 1rem;
color: white;
background: #343a40;
cursor: pointer;
margin-right: 1rem;
}
.grayButton:hover {
background: #adb5db;
}
.skyButton {
border: none;
border-radius: 4px;
font-size: 0.9rem;
font-weight: bold;
padding: 0.4rem 1rem;
color: white;
background: #22b8cf;
cursor: pointer;
margin-right: 1rem;
}
.skyButton:hover {
background: #3bc9db;
}
1-4. 로그인한 정보를 세션에 넣어줄 수 있도록 하겠다.
서버에서도 할 수 있지만 클라이언트 쪽에서 작업하겠다.
- C:\data\react\blog\client\src\components\Auth.js
....
const Auth = () => {
....
const onSubmit = (e) =>{
....
axios.get(`/auth/${userid}`)
.then(res => {
if(res.data.length===1){
if(res.data[0].password === password){
setError('로그인 성공');
alert('로그인 되었습니다.')
sessionStorage.setItem('userid', res.data[0].userid);
window.location.replace('/')
}else{
setError('비밀번호가 일치하지 않습니다.')
}
}else{
setError('해당 아이디가 존재하지 않습니다.')
}
});
}
return (
<div className="authBlock">
....
</div>
);
};
export default Auth;
- C:\data\react\blog\client\src\components\Header.js
import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import '../css/Header.css';
const Header = () => {
// userid store state var
const [userid,setUserid] = useState('');
useEffect(()=>{
setUserid(sessionStorage.getItem('userid'));
},[userid])
const onLogout = () => {
sessionStorage.removeItem('userid');
setUserid('');
}
return (
<div className="headerBlock">
<div className="logo">
<Link to ='/'>REACTERS</Link>
</div>
{userid ? (
<div className="right">
<div>
<span className="userinfo">{userid}</span>
<button className="grayButton" onClick={onLogout}>로그아웃</button>
</div>
</div>
):(
<div className="right">
<Link to="/login">
<button className="grayButton">로그인</button>
</Link>
</div>
)}
</div>
);
};
export default Header;
https://wooogy-egg.tistory.com/49
리액트 - history.push() 이후 refresh 안되는 문제
https://binaryjourney.tistory.com/15?category=916264 문제 현재 윗글 블로거 님의 글을 보면서 내가 개발하려는 서비스에 맞춰서 진행을 하고 있었다. (현재 개발하고 있는 서비스는 게시판 서비스와 동일하
wooogy-egg.tistory.com
2. 게시글 목록을 출력하는 포스트 리스트를 만들어보자.
- sql문을 수정
- C:\data\react\blog\routes\posts.js
const express = require('express');
const router = express.Router();
const db = require('../server');
//게시글목록
router.get('/', (req, res) => {
var sql = 'select * from tbl_post oreder by id desc';
db.con.query(sql, (err, rows) => {
res.send(rows);
})
})
module.exports = router;
- C:\data\react\blog\client\src\components\PostList.js
import axios from 'axios';
import React, { useEffect, useState } from 'react';
const PostList = () => {
const [posts,setPosts] = useState([]);
const [loading,setLoading] = useState(false);
const callAPI = async() => {
setLoading(true);
try {
const res = await axios.get('/post/');
setPosts(res.data);
setLoading(false);
} catch (error) {
console.log(error);
setLoading(false);
}
}
useEffect(()=>{
callAPI();
},[]);
if(loading){
return <div className="postListBlock">Loading...</div>
}
return (
<div className="postListBlock">
{posts ? <textarea value={JSON.stringify(posts,null,2)}/>:''}
</div>
);
};
export default PostList;
- 데이터에 CSS를 주도록 하겠다.
- C:\data\react\blog\client\src\components\PostList.js
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import '../css/PostList.css';
// 내부 컴포넌트
const PostItem = ({post}) => {
const {id,userid,title,body,createDate, fcreateDate} = post;
return(
<div className="postItemBlock">
<h2>{title}</h2>
<div className="subInfo">
<span><b>{userid}</b></span>
<span>{fcreateDate}</span>
</div>
<p>
{body}
</p>
</div>
)
}
const PostList = () => {
const [posts,setPosts] = useState([]);
const [loading,setLoading] = useState(false);
const callAPI = async() => {
setLoading(true);
try {
const res = await axios.get('/post/');
setPosts(res.data);
setLoading(false);
} catch (error) {
console.log(error);
setLoading(false);
}
}
useEffect(()=>{
callAPI();
},[]);
if(loading){
return <div className="postListBlock">Loading...</div>
}
return (
<div className="postListBlock">
{posts ? posts.map(post=><PostItem key={post.id} post={post}/>):''}
</div>
);
};
export default PostList;
- C:\data\react\blog\client\src\css\PostList.css
.postListBlock {
margin-top: 1rem;
overflow: hidden;
}
.buttonWrapper {
overflow: hidden;
margin-bottom: 1rem;
text-align: right;
}
.postItemBlock {
padding: 2rem;
border-bottom: 1px solid #e2e2e2;
}
.postItemBlock .subInfo {
margin-top: 0.5rem;
color: #8a8585;
}
.postItemBlock h2 {
font-size: 2rem;
margin-top: 1rem;
margin-bottom: 0;
}
.postItemBlock h2 a {
color: gray;
}
.postItemBlock h2 a:hover {
color: #bebebe;
}
.postItemBlock p {
margin-top: 2rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.subInfo span {
padding-left: 0.25rem;
padding-right: 0.25rem;
}
- 날자포맷수정
- C:\data\react\blog\routes\posts.js
const express = require('express');
const router = express.Router();
const db = require('../server');
//게시글목록
router.get('/', (req, res) => {
var sql = 'select *,date_format(createDate,"%Y-%m-%d %H:%i:%s") fcreateDate from tbl_post order by id desc';
db.con.query(sql, (err, rows) => {
res.send(rows);
})
})
module.exports = router;
https://www.w3schools.com/mysql/func_mysql_date_format.asp
MySQL DATE_FORMAT() Function
MySQL DATE_FORMAT() Function ❮ MySQL Functions Definition and Usage The DATE_FORMAT() function formats a date as specified. Syntax DATE_FORMAT(date, format) Parameter Values Parameter Description date Required. The date to be formatted format Required. T
www.w3schools.com
- 페이지 이동 컴포넌트를 만들겠다.
- 일단 데이터 단순 자가복제 insert 작업을 하겠다.
- Mysql
#2021.09.17
insert into tbl_post(userid,title,body)
select userid, title, body from tbl_post;
#확인
select count(*) from tbl_post;
- routes sql문 수정
- C:\data\react\blog\routes\posts.js
const express = require('express');
const router = express.Router();
const db = require('../server');
//게시글목록
router.get('/', (req, res) => {
var sql = 'select *,date_format(createDate,"%Y-%m-%d %H:%i:%s") fcreateDate';
sql += ' from tbl_post order by id desc limit 0,2';
db.con.query(sql, (err, rows) => {
res.send(rows);
})
})
module.exports = router;
- pagination component를 만들겠다.
- C:\data\react\blog\client\src\components\(new)Pagination.js
import React from 'react';
import '../css/Pagination.css'
const Pagination = () => {
return (
<div className="paginationBlock">
<button className="grayButton"><</button>
<span>1/96</span>
<button className="grayButton">></button>
</div>
);
};
export default Pagination;
- C:\data\react\blog\client\src\css\(new)Pagination.css
.paginationBlock {
width: 320px;
margin: 0 auto;
display: flex;
justify-content: space-between;
margin-bottom: 3rem;
margin-top: 1rem;
}
.paginationBlock button:disabled {
background: #adb5db;
}
- 페이지를 변경하면 출력값도 바뀌게 하겠다.
- C:\data\react\blog\routes\posts.js
const express = require('express');
const router = express.Router();
const db = require('../server');
// 1. 게시글 목록
router.get('/', (req, res) => {
var page = parseInt(req.query.page);
var start = (page-1)*2
var sql = 'select *,date_format(createDate,"%Y-%m-%d %H:%i:%s") fcreateDate';
sql += ' from tbl_post order by id desc limit ?,2';
db.con.query(sql,[start] ,(err, rows) => {
res.send(rows);
})
})
module.exports = router;
- 쿼리 문자열을 객체로 변환을 위한 qs라는 라이브러리를 아래와 같이 설치한다.
// 클라이언트 진입
C:\data\react\blog>cd client
// qs 라이브러리 설치
C:\data\react\blog\client>yarn add qs
- C:\data\react\blog\client\src\components\PostList.js
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import '../css/PostList.css';
import Pagination from './Pagination';
import {withRouter} from 'react-router-dom';
import qs from 'qs';
// 내부 컴포넌트
const PostItem = ({post}) => {
const {id,userid,title,body,fcreateDate} = post;
return(
<div className="postItemBlock">
<h2>{id} : {title}</h2>
<div className="subInfo">
<span><b>{userid}</b></span>
<span>{fcreateDate}</span>
</div>
<p>
{body}
</p>
</div>
)
}
const PostList = ({location}) => {
const [posts,setPosts] = useState([]);
const [loading,setLoading] = useState(false);
const query = qs.parse(location.search, {ignoreQueryPrefix:true})
const page = !query.page ? 1 : query.page;
const callAPI = async() => {
setLoading(true);
try {
const res = await axios.get(`/post?page=${page}`);
setPosts(res.data);
setLoading(false);
} catch (error) {
console.log(error);
setLoading(false);
}
}
useEffect(()=>{
callAPI();
},[page]);
if(loading){
return <div className="postListBlock">Loading...</div>
}
return (
<div className="postListBlock">
{posts ? posts.map(post=><PostItem key={post.id} post={post}/>):''}
<Pagination page={page}/>
</div>
);
};
export default withRouter(PostList);
- C:\data\react\blog\client\src\components\Pagination.js
import '../css/Pagination.css'
import { Link } from 'react-router-dom';
import React from 'react';
const Pagination = ({page}) => {
var intPage = parseInt(page);
return (
<div className="paginationBlock">
<Link to={`/?page=${intPage-1}`}>
<button className="grayButton"><</button>
</Link>
<span>{page}/96</span>
<Link to={`/?page=${intPage+1}`}>
<button className="grayButton">></button>
</Link>
</div>
);
};
export default Pagination;
- 첫페이지 마지막 페이지에서 버튼이 disabled하게 하겠다.
- C:\data\react\blog\routes\posts.js
// 2. 게시글의 전체 갯수를 구하는 메서드
router.get('/count',(req,res)=>{
var sql = "select count(*) total from tbl_post";
db.con.query(sql,(err,rows)=>{
res.send(rows[0]);
})
})
- C:\data\react\blog\client\src\components\Pagination.js
import '../css/Pagination.css'
import { withRouter } from 'react-router-dom';
import React from 'react';
const Pagination = ({page, lastPage,history}) => {
var intPage = parseInt(page);
var intLastPage = parseInt(lastPage);
const onNext=()=>{
history.push(`/?page=${intPage+1}`)
}
const onPrev=()=>{
history.push(`/?page=${intPage-1}`)
}
return (
<div className="paginationBlock">
<button className="grayButton" disabled={intPage===1} onClick={onPrev}><</button>
<span>{page}/{lastPage}</span>
<button className="grayButton" disabled={intPage===intLastPage} onClick={onNext}>></button>
</div>
);
};
export default withRouter(Pagination);
- 새글 작성하기 버튼을 만들고 새글까지 작성하는 작업을 해보겠다.
- C:\data\react\blog\client\src\components\PostList.js
return (
<div className="postListBlock">
<div className="buttonWrapper">
<button className="skyButton">새글 작성하기</button>
</div>
{posts ? posts.map(post=><PostItem key={post.id} post={post}/>):''}
<Pagination page={page} lastPage={lastPage}/>
</div>
);
- C:\data\react\blog\client\src\components\PostList.js
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import '../css/PostList.css';
import Pagination from './Pagination';
import {Link, withRouter} from 'react-router-dom';
import qs from 'qs';
// 내부 컴포넌트
const PostItem = ({post}) => {
const {id,userid,title,body,fcreateDate} = post;
return(
<div className="postItemBlock">
<h2>{id} : {title}</h2>
<div className="subInfo">
<span><b>{userid}</b></span>
<span>{fcreateDate}</span>
</div>
<p>
{body}
</p>
</div>
)
}
const PostList = ({location}) => {
const [posts,setPosts] = useState([]);
const [loading,setLoading] = useState(false);
const [lastPage,setLastPage] = useState(1);
const [userid,setUserid] = useState('');
const query = qs.parse(location.search, {ignoreQueryPrefix:true})
const page = !query.page ? 1 : query.page;
const callAPI = async() => {
setLoading(true);
try {
var res = await axios.get(`/post?page=${page}`);
setPosts(res.data);
res = await axios.get(`/post/count`);
setLastPage(Math.ceil(parseInt(res.data.total)/2));
setLoading(false);
} catch (error) {
console.log(error);
setLoading(false);
}
}
useEffect(()=>{
callAPI();
setUserid(sessionStorage.getItem('userid'));
},[page]);
if(loading){
return <div className="postListBlock">Loading...</div>
}
return (
<div className="postListBlock">
<div className="buttonWrapper">
<Link to={userid ? '/wirte':'/login'}>
<button className="skyButton">새글 작성하기</button>
</Link>
</div>
{posts ? posts.map(post=><PostItem key={post.id} post={post}/>):''}
<Pagination page={page} lastPage={lastPage}/>
</div>
);
};
export default withRouter(PostList);
- C:\data\react\blog\client\src\components\(new)Write.js
import React from 'react';
const Write = () => {
return (
<div>
<h1>글쓰기</h1>
</div>
);
};
export default Write;
- C:\data\react\blog\client\src\pages\(new)WritePage.js
import React from 'react';
import Header from '../component/Header.js'
import Write from '../components/Write.js';
const WritePage = () => {
return (
<div>
<Header/>
<Write/>
</div>
);
};
export default WritePage;
- 만든 라우트를 app.js에서 등록
- C:\data\react\blog\client\src\App.js
import './App.css';
import { Route } from 'react-router-dom'
import LoginPage from './pages/LoginPage';
import RegisterPage from './pages/RegisterPage';
import PostListPage from './pages/PostListPage';
import WritePage from './pages/WritePage';
function App() {
return (
<div className="App">
<Route path="/" component={PostListPage} exact={true}/>
<Route path="/login" component={LoginPage}/>
<Route path="/register" component={RegisterPage}/>
<Route path="/wirte" component={WritePage}/>
</div>
);
}
export default App;
- 로그아웃시 초기화면으로
- C:\data\react\blog\client\src\components\Header.js
....
const onLogout = () => {
sessionStorage.removeItem('userid');
setUserid('');
window.location.replace('/');
}
....
- 글쓰기 html 꾸미기
- C:\data\react\blog\client\src\components\Write.js
import React from 'react';
import '../css/Write.css';
const Write = () => {
return (
<div className="postWriteBlock">
<form className="postForm">
<input type="text" placeholder="제목을 입력하세요."/>
<textarea placeholder="내용을 입력하세요."></textarea>
<div className="postButtonWrapper">
<button className="skyButton">포스트 등록</button>
<button className="skyButton">취소</button>
</div>
</form>
</div>
);
};
export default Write;
- title, body, userid를 이용해 게시글을 입력하여 db에 입력할 수 있도록 하겠다.
- C:\data\react\blog\client\src\components\Write.js
import React, { useState } from 'react';
import '../css/Write.css';
const Write = () => {
const[form,setForm] = useState({
userid: sessionStorage.getItem('userid'),
title:'',
body:''
});
const {userid, title, body} = form;
const onChange =(e)=>{
setForm({
...form,
[e.target.name]:e.target.value
})
}
const onSubmit = (e) => {
e.preventDefault();
if(title===''){
alert('제목을 입력하세요.')
return;
}else if(body===''){
alert('내용을 입력하세요.')
return;
}else{
if(!window.confirm('글을 등록하시겠습니까?')) return;
}
}
return (
<div className="postWriteBlock">
<form className="postForm" onSubmit={onSubmit}>
<input type="text" name="title" value={title} onChange={onChange} placeholder="제목을 입력하세요."/>
<textarea placeholder="내용을 입력하세요." name="body" onChange={onChange}>{body}</textarea>
<div className="postButtonWrapper">
<button type="submit" className="skyButton">포스트 등록</button>
<button type="reset" className="skyButton">취소</button>
</div>
</form>
</div>
);
};
export default Write;
- 게시글 등록 메서드를 생성하겠다.
- 우선 글이 잘 들어오는지 콘솔에 찍어보겠다.
- C:\data\react\blog\routes\posts.js
// 3. 게시글 등록
router.post('/insert',(req,res)=>{
var userid = req.body.userid;
var title = req.body.title;
var body = req.body.body;
console.log(userid, title, body);
// var sql = "insert into tbl_post(userid,title,body) values(?,?,?)";
// db.con.query(sql,[userid,title,body],(err,rows)=>{
// res.send(rows);
// })
})
module.exports = router;
- C:\data\react\blog\client\src\components\Write.js
....
const onSubmit = (e) => {
e.preventDefault();
if(title===''){
alert('제목을 입력하세요.')
return;
}else if(body===''){
alert('내용을 입력하세요.')
return;
}else{
if(!window.confirm('글을 등록하시겠습니까?')) return;
}
axios.post('/post/insert',form).then(res=>{
alert('글이 등록되었습니다.');
window.location.replace('/')
});
}
....
- 이제 라우트스에서 sql문을 이용해 데이터를 db에 넣어보겠다.
- C:\data\react\blog\routes\posts.js
// 3. 게시글 등록
router.post('/insert',(req,res)=>{
var userid = req.body.userid;
var title = req.body.title;
var body = req.body.body;
var sql = "insert into tbl_post(userid,title,body) values(?,?,?)";
db.con.query(sql,[userid,title,body],(err,rows)=>{
res.send(rows);
})
})
- 이제 특정 게시글을 클릭하여 내용을 읽을 수 있도록 하겠다.
- 게시글을 읽는 라우터를 만들어 만들어보겠다.
- C:\data\react\blog\routes\posts.js
.....
// 4. 게시글 읽기
router.get('/view/:postid', (req, res) => {
var id = req.params.postid
var sql = 'select *,date_format(createDate,"%Y-%m-%d %H:%i:%s") fcreateDate from tbl_post where id=?';
db.con.query(sql,[id] ,(err, rows) => {
res.send(rows[0]);
})
})
module.exports = router;
- C:\data\react\blog\client\src\components\(new)Viewer.js
import React from 'react';
import '../css/Viewer.css'
const Viewer = () => {
return (
<div className="viewerWriteBlock">
<form className="viewerForm">
<input type="text" name="title"/>
<div className="subInfo">
<span></span>
<span></span>
</div>
<textarea name="body"></textarea>
</form>
</div>
);
};
export default Viewer;
- C:\data\react\blog\client\src\pages\(new)ViewerPage.js
import React from 'react';
import Viewer from '../components/Viewer';
import Header from '../components/Header';
const ViewerPage = () => {
return (
<div>
<Header/>
<Viewer/>
</div>
);
};
export default ViewerPage;
- C:\data\react\blog\client\src\App.js
import './App.css';
import { Route } from 'react-router-dom'
import LoginPage from './pages/LoginPage';
import RegisterPage from './pages/RegisterPage';
import PostListPage from './pages/PostListPage';
import WritePage from './pages/WritePage';
import ViewerPage from './pages/ViewerPage';
function App() {
return (
<div className="App">
<Route path="/" component={PostListPage} exact={true}/>
<Route path="/login" component={LoginPage}/>
<Route path="/register" component={RegisterPage}/>
<Route path="/wirte" component={WritePage}/>
<Route path="/view/:postid" component={ViewerPage}/>
</div>
);
}
export default App;
- 이제 viewer.js를 디자인해보자.
- C:\data\react\blog\client\src\css\(new)Viewer.css
.viewerWriteBlock {
overflow: hidden;
}
.viewerForm {
padding: 1rem;
}
.viewerForm input {
width: 100%;
font-size: 2rem;
border: none;
outline: none;
margin-top: 3rem;
padding-bottom: 1rem;
}
.viewerForm input:hover {
border-bottom: 1px solid #495057;
}
.viewerForm textarea {
font-family: inherit;
width: 100%;
font-size: 1.2rem;
margin-top: 2rem;
min-height: 300px;
border: none;
outline: none;
border-bottom: 1px solid #e2e2e2;
}
.viewerForm textarea:hover {
border-bottom: 1px solid #495057;
}
.viewerForm .subInfo {
margin-top: 1rem;
color: #495057;
padding-bottom: 1rem;
border-bottom: 1px solid #e2e2e2;
}
- 특정 게시글의 아이디를 이용해 /view/id 로 이동할 수 있도록 하겠다.
- C:\data\react\blog\client\src\components\PostList.js
.....
const PostItem = ({post}) => {
const {id,userid,title,body,fcreateDate} = post;
return(
<div className="postItemBlock">
<h2><Link to={`/view/${id}`}>{id} : {title}</Link></h2>
<div className="subInfo">
<span><b>{userid}</b></span>
<span>{fcreateDate}</span>
</div>
<p>
{body}
</p>
</div>
)
}
.....
- C:\data\react\blog\client\src\components\Viewer.js
import React, { useEffect, useState } from 'react';
import '../css/Viewer.css'
import { withRouter } from 'react-router';
import axios from 'axios';
const Viewer = ({match}) => {
const {postid} = match.params;
const [form,setForm] = useState({
id:0,
userid:'',
title:'',
body:'',
fcreateDate:''
})
const{id,userid,title,body,fcreateDate} = form;
const callAPI = async() =>{
try {
const res = await axios.get(`/post/view/${postid}`);
setForm(res.data);
} catch (error) {
console.log(error);
}
}
useEffect(()=>{
callAPI();
},[postid])
return (
<div className="viewerWriteBlock">
<form className="viewerForm">
<input type="text" name="title" value={title}/>
<div className="subInfo">
<span><b>{userid}</b></span>
<span>{fcreateDate}</span>
</div>
<textarea name="body" value={body}></textarea>
</form>
</div>
);
};
export default withRouter(Viewer);
- 이제 업데이트 작업을 해보도록 하겠다.
- 수정, 삭제 컴포넌트를 따로 만들겠다.
- C:\data\react\blog\client\src\components\(new)Update.js
import React from 'react';
import '../css/Update.css'
const Update = () => {
return (
<div className="postUpdate">
<span>수정</span>
<span>삭제</span>
</div>
);
};
export default Update;
- C:\data\react\blog\client\src\css\(new)Update.css
.postUpdate {
overflow: hidden;
margin-top: 1rem;
text-align: right;
}
.postUpdate span {
font-size: 0.875rem;
color: #495057;
padding: 0.3rem;
cursor: pointer;
}
.postUpdate span:hover {
color: #e2e2e2;
}
- C:\data\react\blog\client\src\components\Viewer.js
....
import Update from './Update';
const Viewer = ({match}) => {
....
const loginId = sessionStorage.getItem('userid');
....
....
return (
<div className="viewerWriteBlock">
<form className="viewerForm">
<input type="text" name="title" value={title}/>
<div className="subInfo">
<span><b>{userid}</b></span>
<span>{fcreateDate}</span>
</div>
{userid===loginId && <Update/>}
<textarea name="body" value={body}></textarea>
</form>
</div>
);
};
export default withRouter(Viewer);
- C:\data\react\blog\client\src\components\Viewer.js
....
const Viewer = ({match}) => {
....
....
....
....
....
const onChange =(e)=>{
setForm({
...form,
[e.target.name]:e.target.value
})
}
return (
<div className="viewerWriteBlock">
<form className="viewerForm">
<input type="text" name="title" onChange={onChange} value={title} disabled={userid !== loginId}/>
<div className="subInfo">
<span><b>{userid}</b></span>
<span>{fcreateDate}</span>
</div>
{userid===loginId && <Update/>}
<textarea name="body" onChange={onChange} value={body} disabled={userid !== loginId}></textarea>
</form>
</div>
);
};
export default withRouter(Viewer);
- form 데이터를 Update.js에 넣어가지고 가도록 하겠다.
- C:\data\react\blog\client\src\components\Viewer.js
return (
<div className="viewerWriteBlock">
<form className="viewerForm">
<input type="text" name="title" onChange={onChange} value={title} disabled={userid !== loginId}/>
<div className="subInfo">
<span><b>{userid}</b></span>
<span>{fcreateDate}</span>
</div>
{userid===loginId && <Update post={form}/>}
<textarea name="body" onChange={onChange} value={body} disabled={userid !== loginId}></textarea>
</form>
</div>
);
- C:\data\react\blog\client\src\components\Update.js
import React from 'react';
import '../css/Update.css'
const Update = ({post}) => {
const { id, title, body } = post;
const onUpdate = (e) => {
e.preventDefault();
if(!window.confirm('글을 수정하시겠습니까?')) return;
}
const onDelete = (e) => {
e.preventDefault();
if(!window.confirm('글을 삭제하시겠습니까?')) return;
}
return (
<div className="postUpdate">
<span onClick={onUpdate}>수정</span>
<span onClick={onDelete}>삭제</span>
</div>
);
};
export default Update;
- 이제 글 삭제 수정하는 라우터를 만들도록 하겠다.
- C:\data\react\blog\routes\posts.js
.....
// 5. 게시글 삭제
router.post('/delete',(req,res)=>{
var id = req.body.id
var sql = "delete from tbl_post where id=?";
db.con.query(sql,[id],(err,rows)=>{
res.send(rows);
})
})
// 6. 게시글 수정
router.post('/update',(req,res)=>{
var id = req.body.id;
var title = req.body.title;
var body = req.body.body;
var sql = "update tbl_post set title=?,body=? where id=?";
db.con.query(sql,[title,body,id],(err,rows)=>{
res.send(rows);
})
})
module.exports = router;
- C:\data\react\blog\client\src\components\Update.js
import axios from 'axios';
import React from 'react';
import '../css/Update.css'
const Update = ({post}) => {
const { id, title, body } = post;
const onUpdate = (e) => {
e.preventDefault();
if(!window.confirm('글을 수정하시겠습니까?')) return;
axios.post('/post/update',post).then(res=>{
alert('수정되었습니다.');
window.location.replace('/');
})
}
const onDelete = (e) => {
e.preventDefault();
if(!window.confirm('글을 삭제하시겠습니까?')) return;
axios.post('/post/delete',post).then(res=>{
alert('삭제되었습니다.');
window.location.replace('/')
})
}
return (
<div className="postUpdate">
<span onClick={onUpdate}>수정</span>
<span onClick={onDelete}>삭제</span>
</div>
);
};
export default Update;
- 검색하는 작업을 해보겠다.
'ICIA 수업일지' 카테고리의 다른 글
2021.09.24 수업일지(안드로이드 개발 기초, SQLite) (0) | 2021.09.24 |
---|---|
2021.09.23 수업일지(안드로이드 개발 기초, Activity, View) (0) | 2021.09.23 |
2021.09.16 수업일지(React.js) (0) | 2021.09.16 |
2021.09.15 수업일지(React.js) (0) | 2021.09.15 |
2021.09.14 수업일지(React.js) (0) | 2021.09.14 |