오늘은 지금까지 react 에서 공부했던 redux, mysql 를 이용하여 이전 게시물에서 구현할 것이다.
이전에 redux 를 이용하여 구현했던 예제 그대로 사용할 것이다.
2021/01/31 - [React] - [React] DB에서 특정 데이터 받아오기 - 떽떽대는 개발공부
이전 글에서 MySQL 을 이용하여 글 목록 가져오는 것, 특정 글을 클릭했을 때 해당 글에 대한 데이터를 받아오는 것까지 포스팅 했었다.
그러나 치명적인 문제가 발생했는데, api 호출하여 특정 데이터를 받아오는 데에 시간이 너무 오래 걸린다는 것이다.
그래서 나는 글 목록 페이지에 들어왔을 때 DB에 있는 데이터를 redux-store 에 미리 초기화 시킨 후 특정 글 클릭 시 store 에서 데이터를 빼오도록 변경하였다.
src/components/BoardList.js
import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';
import { init_Data, init_lastIdx, selectRow } from '@modules/boardReducer';
import axios from 'axios';
function BoardList() {
// db에서 받아올 데이터를 담을 그릇
const [initData, setInitData] = useState([{
inputData: {
idx: '',
title: '',
content: '',
writer: '',
write_date: ''
},
}])
// 원활한 데이터 관리를 위해 글 갯수를 파악한다.
const [initLastIdx, setInitLastIdx] = useState(0)
useEffect(async() => {
try{
const res = await axios.get('/api/BoardList')
const _inputData = await res.data.map((rowData) => (
// 마지막 rowData의 idx 가 lastIdx 가 될 것이다.
setInitLastIdx(rowData.idx),
{
idx: rowData.idx,
title: rowData.title,
content: rowData.content,
writer: rowData.writer,
write_date: rowData.write_date
})
)
// initData 그릇에 concat 으로 추가해준다.
setInitData(initData.concat(_inputData))
} catch(e){
console.error(e.message)
}
},[])
// initData 가 set 될 때마다 boardReducer 의 init_Data와 init_Idx 함수가 호출된다.
useEffect(() => {
dispatch(init_Data(initData))
dispatch(init_lastIdx(initLastIdx))
}, [initData])
//////////////////////////////////////////////////////////////////////////
store 에 데이터 init 이후
//////////////////////////////////////////////////////////////////////////
// store 에 저장된 데이터 받아오기
const {inputData} = useSelector(state => state.boardReducer)
const {lastIdx} = useSelector(state => state.boardReducer)
// 함수형 컴포넌트에서 useDispatch 를 사용하기 위해 선언
const dispatch = useDispatch();
// 특정 글 클릭되면 boardReducer의 selectRow에 dispatch
const selectContent = (idx) => {
dispatch(selectRow(idx))
}
return(
<div>
<h2>게시판</h2>
<div>
<table className='listTable'>
<tbody>
<tr>
<td className='listTableIndex th'>index</td>
<td className='listTableTitle th'>title</td>
</tr>
{lastIdx !== 0 ?
inputData.map(rowData => (
rowData.idx !== '' && rowData.idx !== undefined &&
<tr>
<td className='listTableIndex' onClick={() => {selectContent(rowData.idx)}}>
<Link to={`/BoardContent/${rowData.idx}`}>{rowData.idx}</Link>
</td>
<td className='listTableTitle' onClick={() => {selectContent(rowData.idx)}}>
<Link to={`/BoardContent/${rowData.idx}`}>{rowData.title}</Link>
</td>
</tr>
)) :
<tr>
<td className='listTableIndex'></td>
<td className='listTableTitle noData'>작성된 글이 없습니다.</td>
</tr>
}
</tbody>
</table>
</div>
</div>
)
}
export default BoardList;
위와 같이 먼저 BoardList 페이지가 렌더 되면 axios를 톹해 '/api/BoardList'의 api 로 db 요청을 하게 된다.
이제 db 요청을 받을 페이지를 수정한다.
server/routes/index.js
const express = require('express');
const router = express();
const db = require('../config/db')
// http://localhost:4000/ 으로 접속 시 응답메시지 출력
router.get('/BoardList', (req,res) => {
const sql = 'SELECT idx, title, content, writer, write_date FROM table1';
db.query(sql, (err, data) => {
if(!err){
res.send(data);
} else {
res.send(err);
}
})
})
module.exports = router;
클라이언트에서 요청한 호출을 proxy 를 이용하여 서버단에서 받아왔다.
proxy 를 이용하는 법은 전에 포스팅 해 두었다.
이렇게 하면 아래와 같이 리스트 구현이 완료 된다.
이제 db의 값을 store 에도 저장해 두었기 때문에 특정 글 클릭 시 페이지 이동 후 보여질 페이지는 store 에서 받아올 것이다.
이제 글 상세보기 페이지에서 보자.
src/components/BoardContent.js
import React, { useState, useEffect } from 'react';
import { useSelector } from 'react-redux'
import axios from 'axios';
function BoardContent({match}) {
// store 에 저장된 데이터를 받아온다.
const { selectRowData } = useSelector(state => state.boardReducer)
// 받아온 데이터를 각각 관리
const [idx, setIdx] = useState(selectRowData.idx)
const [title, setTitle] = useState(selectRowData.title)
const [content, setContent] = useState(selectRowData.content)
const [writer, setWriter] = useState(selectRowData.writer)
const [date, setDate] = useState(selectRowData.write_date)
const handleTitle = (e) => {
setTitle(e.target.value)
}
const handleContent = (e) => {
setContent(e.target.value)
}
const handleWriter =(e) => {
setWriter(e.target.value)
}
// date 가 호출될 때마다 함수 실행
// date 뒤에 시간을 지울 것이다.
useEffect(() => {
setDate(date.split('T')[0])
}, [date])
const onChange = async() => {
// edit 버튼 클릭 시 ghcnf
try{
// axios.post 는 config 로 받아갈 값이 3번째의 매개변수이기 때문에 data 를 임의로 넣어주었다.
const res = await axios.post('/api/BoardUpdate', {'data':'data'}, {
params: {
'idx': idx,
'title': title,
'content': content,
'writer': writer,
'write_date': date
}
})
// DB로 관리할 것이기 때문에 useHistory 말고 document.location.href 로 페이지 이동(새로고침 가능)
document.location.href='/'
} catch(e) {
console.error(e.message)
}
}
const onRemove = async() => {
// delete 버튼 를릭 시 실행
try{
// axios.get 은 두번째 매개변수로 config 전달
const res = await axios.get('/api/BoardDelete', {
params: {
'idx': idx
}
})
console.log('delete :: result :: ',res)
document.location.href='/'
} catch(e) {
console.error(e.message)
}
}
return(
<div>
<h2>상세보기</h2>
<div>
<div>
<label for='title'>제목</label>
<input type='text' name='title' className='inputTitle' value={title} onChange={handleTitle} />
</div>
<div>
<label for='writer'>작성자</label>
<input type='text' name='title' className='inputWriter' value={writer} onChange={handleWriter} />
</div>
<div>
<label for='writer'>작성일</label>
<input type='text' name='title' className='inputWriter' value={date} disabled />
</div>
<div>
<label className='_content' for='content'>내용</label>
<textarea name='content' className='inputContent' value={content} onChange={handleContent} />
</div>
<div>
<button type='button' className='editBtn' onClick={onChange}>edit</button>
<button type='button' className='deleteBtn' onClick={onRemove}>delete</button>
</div>
</div>
</div>
)
}
export default BoardContent;
호출을 받은 서버에도 코드를 수정해준다.
server.routes/index.js
const express = require('express');
const router = express();
const db = require('../config/db')
// http://localhost:4000/ 으로 접속 시 응답메시지 출력
router.get('/BoardList', (req,res) => {
const sql = 'SELECT idx, title, content, writer, write_date FROM table1';
db.query(sql, (err, data) => {
if(!err){
res.send(data);
} else {
res.send(err);
}
})
//res.send({ test : "this is test!!"});
})
// store 로 db 관리를 함으로 호출할 필요 없다.
//router.get('/BoardContent', (req,res) => {
// const sql = 'SELECT idx, title, content, writer, write_date FROM `table1` WHERE `idx` = ?';
// const params = req.query.idx
// db.query(sql, params, (err, data) => {
// if(!err) {
// res.send(data)
// } else {
// res.send(err)
// }
// })
//})
// log 찍기 위해 사용..
const util = require('util')
router.post('/BoardUpdate', (req, res) => {
const sql = 'UPDATE `table1` SET `title` = ?, `content` = ?, `writer` = ?, `write_date` = ? WHERE `idx` = ?';
const params = [req.query.title, req.query.content, req.query.writer, req.query.write_date, req.query.idx]
console.log(`= = =>req ${util.inspect(req.query)}`)
db.query(sql, params, (err, data) => {
if(!err) {
res.send(data)
} else {
res.send(err)
}
})
})
router.get('/BoardDelete', (req,res) => {
const sql = 'DELETE FROM `table1` WHERE `idx` = ?';
const params = req.query.idx
db.query(sql, params, (err, data) => {
if(!err) {
res.send(data)
} else {
res.send(err)
}
})
})
module.exports = router;
이렇게 하면 글 상세보기 페이지에서 수정, 삭제가 가능하다.
이제 글 추가만 더 해보자.
src/components/BoardNew.js
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import axios from 'axios';
function BoardNew() {
// 현재 날짜 받아오기
const today = new Date().toISOString().substr(0,10).replace('T', ' ')
const [title, setTitle] = useState('')
const [writer, setWriter] = useState('')
const [content, setContent] = useState('')
// store 에서 마지막 idx 받아온다
const {lastIdx} = useSelector(state => state.boardReducer)
const handleTitle = (e) => {
setTitle(e.target.value)
}
const handleWriter = (e) => {
setWriter(e.target.value)
}
const handleContent = (e) => {
setContent(e.target.value)
}
const onSave = async() => {
try{
const res = await axios.post('/api/BoardInsert', {'data':'data'}, {
params: {
// store 에서 받아온 마지막 idx에서 1을 추가
'idx': lastIdx+1,
'title': title,
'content': content,
'writer': writer,
'write_date': today
}
})
document.location.href='/'
} catch(e) {
console.error(e.message)
}
}
return(
<div>
<h2>글 작성</h2>
<div>
<div>
<input type='text' className='inputTitle' placeholder='제목을 입력하세요' value={title} onChange={handleTitle} />
</div>
<div>
<input type='text' className='inputTitle' placeholder='작성자를 입력하세요' value={writer} onChange={handleWriter} />
</div>
<div>
<textarea className='inputContent' placeholder='내용을 입력하세요' value={content} onChange={handleContent} />
</div>
<div>
<button type='button' onClick={onSave}>submit</button>
</div>
</div>
</div>
)
}
export default BoardNew;
이제 이로써 게시판 예제를 가지고 redux, MySQL 을 이용한 방법을 모두 해 보았다.
다음엔 어떤걸로 포스팅 할 지 조금 더 생각 해보자.
'React' 카테고리의 다른 글
[React] react 에서 로그인 페이지 구현하기(2) - 떽떽대는 개발공부 (3) | 2021.02.10 |
---|---|
[React] react 에서 로그인 페이지 구현하기 (1) - 떽떽대는 개발공부 (2) | 2021.02.09 |
[React] DB에서 특정 데이터 받아오기 - 떽떽대는 개발공부 (0) | 2021.01.31 |
[React] DB에서 받아온 데이터 리스트 만들기 - 떽떽대는 개발공부 (0) | 2021.01.30 |
[React/MySQL] react 에서 MySQL 사용하기 - 떽떽대는 개발공부 (0) | 2021.01.29 |
댓글