2022-12-25 22์ ์ ์ถ ์๋ฃ
์ค๋ง์ผ๊ฒ์ดํธ ์ํฐ ๋ฐ๋ธ์บ ํ์์ ํ ํ๋ก์ ํธ ์ ์งํํ๋ 1์ธ ํ๋ก์ ํธ์
๋๋ค.
์ข์ํ๋ ๋
ธ๋๋ฅผ ์ถ์ฒํด์ฃผ๊ณ ๋ชฐ๋๋ ๋
ธ๋๋ฅผ ์ถ์ฒ๋ฐ์ ์ ์๋ ๋
ธ๋ ์ถ์ฒ ๋ธ๋ก๊ทธ์
๋๋ค.
react : v18.2.0
nodejs : v18.12.1
MySQL
CREATE DATABASE bbs;
USE bbs;
CREATE TABLE postInfo (
postId int not null auto_increment primary key,
title nvarchar(30),
singer nvarchar(30),
content nvarchar(500),
image nvarchar(500),
userIp nvarchar(20),
registerDate DATETIME DEFAULT now(),
);
USE bbs;
CREATE TABLE replyInfo (
replyId int not null auto_increment primary key,
postId int,
content nvarchar(100),
userIp nvarchar(20),
registerDate DATETIME DEFAULT now()
);
db setting
const mysql = require('mysql');
const db = mysql.createPool({
host: 'localhost',
user: 'root',
password: '1234',
database: 'bbs',
multipleStatements: true,
});
Clone the project and access the folder
$ git clone https://github.com/Jeongseulho/music-blog.git
$ cd music-blog
using naver search open api key
๋ค์ด๋ฒ ๊ฒ์ api ์ด์ฉ ์ ์ฒญ : https://developers.naver.com/products/service-api/search/search.md
$ cd back
$ touch .env
// .env
NAVERIMG_API_ID="YOUR_CLIENT_ID" NAVERIMG_API_SECRET="YOUR_CLIENT_SECRET"
install and run server
$ cd back
$ npm i
$ npm run dev
$ cd front
$ npm i
$ npm start
โ๏ธํ์๋ก ์ถ๊ฐ์ ์ธ ์ ๋ณด ํ์
ํ๋ก ํธ์๋ ๋ชฉํ
- jest, testing library๋ฅผ ์ด์ฉํ ํ๋ก ํธ์๋ ํ
์คํธ์ฐ์ต์ผ๋ก ํ
์คํธ ๋์ ๋ฐ ๋ฐฉ๋ฒ ๊ตฌ์ฒดํ ํ๊ธฐ
โ๏ธ Unit Test๋ง ์ํ, ๋น์ฆ๋์ค ๋ก์ง์ ๋ํด์๋ง ์ํ - ํํ๋ก์ ํธ์์ ์ฌ์ฉํ ๊ธฐ์ ์คํ ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ตํ๊ธฐ
- Redux๋ฅผ ์ฌ์ฉํ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ตํ๊ธฐ
โ๏ธ Redux ๋์ Redux-Toolkit ์ฌ์ฉ - React query๋ฅผ ์ฌ์ฉํ์ฌ sever data, client data ๋ถ๋ฆฌ ์ฐ์ต
โ๏ธ ํ๋ก์ ํธ๊ฐ ์์ RTK-thunk๋ก userIp๋ง ๊ด๋ฆฌ - tailwind css๋ก ๋น ๋ฅด๊ฒ ๋์์ธ ๊ตฌํํ๋ ์ฐ์ต
- Redux๋ฅผ ์ฌ์ฉํ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ตํ๊ธฐ
- ์ปดํฌ๋ํธ ๊ตฌ์กฐ ์ค๊ณ ํจํด๋ค์๋ํด ๊ณต๋ถํ๊ณ ์ ์ ํ ํจํด ์ ํํ๋ ์๋ชฉ ํฅ์์ํค๊ธฐ
- ๋ฆฌ๋ ๋๋ง ๋๋ ๋ ๋๋ง ์๊ฐ ์ต์ํ ์ํค๋ ์ฑ๋ฅ ๊ฐ์ ์๋ํ๊ธฐ
๋ฐฑ์๋ ๋ชฉํ
- ๋ฐฑ์๋์ ํ์
์ ํ์ํ ์ฉ์ด ๋ฐ ๊ธฐ๋ณธ์ง์ ์ตํ๊ธฐ
โ๏ธ mysql์ฌ์ฉ์ผ๋ก table๊ตฌ์กฐ ๊ฐ๋จํ๊ฒ ํ์ , rest api ์ค์ต, req.body vs req.params vs req.query ๋ฐฉ๋ฒ์ ๋ฐ์ดํฐ ๋ณด๋ด๋ ๋ฐฉ๋ฒ ๊ณต๋ถ, cors์๋ฌ ํด๊ฒฐ ๋ฐฉ๋ฒ, proxy ์ค์ ๋ฑ - ํผ์์๋ ํ์คํ์ผ๋ก ๊ฐ๋จํ ์น์ฑ์ ๋ง๋ค ์ ์๋ ๋ฅ๋ ฅ ๊ธฐ๋ฅด๊ธฐ
- MYSQL์ ์ฌ์ฉํ์ฌ ํ์ค SQL ๋ฌธ๋ฒ ์ตํ๊ธฐ
- Node.js(Express.js)์ฌ์ฉํ์ฌ DB์ ์ฐ๊ฒฐ, ๋ฏธ๋ค์จ์ด ์ ์ ๋ฑ์ ๋ํ์ฌ ํ์ตํ๊ธฐ
- ๋ฐฑ์๋์ ํ์
์ ๊ตฌ์ฒด์ ์ผ๋ก ์ด๋ค ๋ถ๋ถ์์ ์ด๋ป๊ฒ ์ํต์ ํ๋ฉด ์ข์์ง ๊ฒฝํํด๋ณด๊ณ ๊ธฐ๋กํ๊ธฐ
โ๏ธ mysql table ์ด ์ด๋ฆ์ ํ๋ก ํธ์์ ์ฌ์ฉํ๋ ๋ณ์ ์ด๋ฆ๊ณผ ํต์ผํ๋ฉด ํธํ ๊ฒ ๊ฐ๋ค, ๋ณ์๋ช ์ ์นด๋ฉ์ผ์ด์ค/์ค๋ค์ดํฌ์ผ์ด์ค ์ค์์ ์ ํ๊ธฐ
๊ทธ ์ธ ๋ชฉํ
- ๋น์ฆ๋์ค ๋ก์ง๊ณผ View์ ๊ตฌ๋ถ ๊ธฐ์ค์ ๋ํด ๊ณ ๋ฏผํ๊ณ 2๊ฐ๋ฅผ ๋ช
ํํ ๋ถ๋ฆฌํ๋ ์ํคํ
์ฒ ์ค๊ณ ๋ฐ ์ฝ๋ ์์ฑํ๊ธฐ
โ๏ธ custom hooks์ผ๋ก page์ ๋ทฐ์ ๋ก์ง ๋ถ๋ฆฌ - ํ๋ก์ ํธ๋ฅผ ํ๋ฉด์ ๊ฒช์ ๋ฌธ์ ์ ๋ฐ ์๋ฌ์ฌํญ๊ณผ ํด๊ฒฐ๋ฐฉ๋ฒ ๊ธฐ๋กํ๋ฉด์ ์งํํ๊ธฐ
๐ฆsrc
โฃ ๐api
โ โฃ ๐etc
โ โฃ ๐post
โ โ ๐reply
โฃ ๐components
โ โฃ ๐admin
โ โฃ ๐etc
โ โ ๐Home
โฃ ๐hooks
โ โฃ ๐etc
โ โฃ ๐useComponents
โ โ ๐usePages
โฃ ๐pages
โฃ ๐redux
โฃ ๐utils
โฃ ๐tests
โ โฃ ๐apiTest
โ โ ๐utilsTest.js
-
- ์ ๋ชฉ์ ์ถ์ฒํ ๋ ธ๋์ ๋ชฉ๊ณผ ๊ฐ์ ์ ๋ ฅ์ผ๋ก ์ธ๋ค์ผ ๊ฒ์ ๊ธฐ๋ฅ(๋ค์ด๋ฒ ์ด๋ฏธ์ง ๊ฒ์ api์ด์ฉ)
- 10๊ฐ์ ์ด๋ฏธ์ง ์ค ์ ํ๊ฐ๋ฅ
-
- default ๊ฐ์ผ๋ก ์ค์ ip ์ฌ์ฉ
- ip ์ค์ ํ๊ธฐ๋ก ip custom ๊ฐ๋ฅ
-
- ๊ธ ์์ , ์ญ์ ๊ถํ์ ์ํด ๊ธ ์์ฑ์ ip์ ๋์ผํด์ผํจ
- ๊ธ ์ญ์ ์ ํด๋น ๋๊ธ ์ ๋ณด ๊ฐ์ด ์ญ์
-
ํ ํ๋ฉด์์ ๊ธ ๋ชฉ๋ก ๋ถ๋ฌ์ค๊ธฐ
- default ๊ฐ์ผ๋ก ์ต๊ทผ ๊ธ ์์ผ๋ก ์ ๋ ฌ
- ๊ธ ๋ชฉ๋ก ํ์ด์ง๋ค์ด์
-
- ํด๋น ๊ธ์ ๊ธ์ด์ด์ธ ๊ฒฝ์ฐ์๋ง ๊ธ์ด์ด ํ์
- ๋๋จธ์ง ๋๊ธ ์์ฑ์๋ค์ ์ต๋ช
์ผ๋ก ํ์
-
- ํด๋น ๋๊ธ ์์ฑํ ip์ ๋์ผํ ๊ฒฝ์ฐ์๋ง ์ญ์ ๊ฐ๋ฅ
- ํด๋น ๋๊ธ ์์ฑํ ip์ ๋์ผํ ๊ฒฝ์ฐ์๋ง ์ญ์ ๊ฐ๋ฅ
-
์ฐจํธ๋ก ์ต๊ทผ 7์ผ๊ฐ ๋ฑ๋ก๋ ๋๊ธ ์, ๊ธ ์ ๋ณด์ฌ์ฃผ๊ธฐ
๐tests - apiTestํด๋์ axios๋ฅผ ํ ์คํธ ํ๋ ์ฝ๋๋ฅผ ์์ฑ ํ๋๋ฐ ์ ๋๋ก ์์ฑํ๊ฑด์ง
๐๋๊ธ์ postํ๋๋ฐ ์ฃผ์๋ฅผ /reply
๋๊ธ ๋ฆฌ์คํธ๋ฅผ getํ๋๋ฐ ์ฃผ์๋ฅผ /reply/:postId
์ด๋ผ ์ ํ๋๋ฐ ๋๊ธ ์ฒ๋ผ ๊ธ์ ์ข
์๋ ์ ๋ณด๋ฅผ rest api ๊ธฐ์ค์ผ๋ก ์ด๋ป๊ฒ ์ ํ ์ง ex) /post/:postId/reply
๐componentsํด๋์ PaginationBtn๋ณด๋ฉด ๋ก์ง์ด ๊ฐ๋จํ๊ณ ์ฝ๋๊ฐ ์งง๋ค๊ณ ์๊ฐํด์ view <-> logic์ useํ ์ผ๋ก ๋นผ์ง ์์๋๋ฐ ์ด๋ ๊ฒ ์งง๊ณ ๊ฐ๋จํ ์ฝ๋์ ๊ฒฝ์ฐ๋ ์ผ๊ด์ฑ์ ์ํด logic์ ๋ถ๋ฆฌํ๋์ง
// ํ์ด์ง๋ค์ด์
๋ฒํผ์์ ๊ฐ ๋ฒํผ(1,2,3...)์ ๋ง๋๋ ๋ถ๋ถ
{Array.from({ length: totalPage }, (_, i) => i + 1).map((pageNum) => (
<li key={pageNum}>
<button
type="button"
className={
currentPage === pageNum
? 'h-10 w-10 rounded-full border border-r-0 border-indigo-600 bg-indigo-600 text-white transition-colors duration-150'
: 'h-10 w-10 rounded-full text-indigo-600 transition-colors duration-150 hover:bg-indigo-100'
}
onClick={() => setCurrentPage(pageNum)}
>
{pageNum}
</button>
</li>
))}
๐usePages์ useAddPost, useEditPost, useViewPost๋ฅผ ๋ณด๋ฉด ๋น์ทํ ๋ถ๋ถ์ด ๋ง์ผ๋ฉด์ ์กฐ๊ธ์ฉ ๋ค๋ฅธ๋ฐ ๋ ์๊ฒ ํ ์ ๋ง๋ค์ด ์ฌ์ฌ์ฉํด์ผ ํ ์ง
๐ํด๋ ๊ตฌ์กฐ์ ๋ํด ๋ถ๋ฅํ๊ธฐ ์ ๋งคํ๋ฉด etcํด๋ ๋ง๋ค๊ณ ํ๊ณณ์ ๋ชจ์๋๋ฐ etcํด๋๋ณด๋ค ์ฌ๋ฌ ์ข ๋ฅ๋ก ๋ค ๋๋๋๊ฒ ๋์์ง
๐๊ธ ๋ชฉ๋ก(์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ)์ ๋ฐ์์์ useState(๋ด๋ถ ๋ฐ์ดํฐ)๋ก ์ฌ์ฉํ๋๋ฐ ์ด๋ฐ ๋ก์ง์ด ์ผ๋ฐ์ ์ธ์ง
ex) ์ญ์ ๊ธฐ๋ฅ์์ ์ญ์ ๋ฒํผ์ ๋๋ฅธํ ๋ฐฑ์๋์ ์ญ์ ๋ฅผ ์์ฒญ ํ ํ
- ์์ฒด์ ์ธ ๊ธ๋ชฉ๋ก(๋ด๋ถ state๋ฐ์ดํฐ)์์ ์ญ์ ๋ฅผ ํด์ ๋ฆฌ๋ ๋๋ง ํ๋ค(์ด๊ฒฝ์ฐ ๋ฐ์์ ์ธ๊ธํ server date <-> client date ๊ตฌ๋ถ ๋ฌธ์ ๋ฐ์)
- ์ญ์ ๋ ์ ๊ธ๋ชฉ๋ก(๋ฐฑ์๋ ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ)๋ฅผ ๋ฐ์์์ ๋ฆฌ๋ ๋๋ง ํ๋ค
๐server date <-> client date ๊ตฌ๋ถ ๋ฌธ์
์ํ๊ด๋ฆฌ๋ฅผ 3๊ฐ์ง๋ก ๋ถ๋ฅํด๋ณด๋ คํ๋๋ฐ
- useState : ๋ด๋ถ ๋ฐ์ดํฐ (props์ ๋ฌ ๋ง์ง ์์ ๊ฒฝ์ฐ)
- redux store : ๋ด๋ถ ๋ฐ์ดํฐ (props์ ๋ฌ์ด ๋ง์ ์ ์ญ์ ์ผ๋ก ์ฌ์ฉํด์ผํ ๊ฒฝ์ฐ)
- rtk query ๋๋ react query : ์๋ฒ ๋ฐ์ดํฐ
์๋ฒ๋ก ๋ถํฐ์ ๋ฐ์ดํฐ๊ธ ๋ชฉ๋ก(๋ฐฑ์๋ ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ)์ ๋ฐ์์์ useState(๋ด๋ถ ๋ฐ์ดํฐ)๋ก ๋ง๋๋ ์๋ฒ๋ฐ์ดํฐ / ๋ด๋ถ๋ฐ์ดํฐ ๊ตฌ๋ถ์ ์ด๋ป๊ฒ ํด์ผํ ์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.
๋ํ, ์ ํ 3๊ฐ์ง๋ก ๋ถ๋ฅํ๋ ์ด๋ฐ์์ผ๋ก ์ํ๊ด๋ฆฌ๋ฅผ ๋๋๋๊ฒ ๋ง๋์ง
๐view<->logic ๊ตฌ๋ถํ๋ hooks์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ, ํ์ด์ง์ ๋์ํ๊ฒ ์ด๋ฆ์ ์ง์๋๋ฐ(ViewPost.jsx - useViewPost.js) ์ฌ์ฌ์ฉ์ฑ์ ์๊ฐํด์ hooks ์ด๋ฆ์ ๋ค๋ฅด๊ฒ ์ง๋๊ฒ ๋์์ง
๐๋ณต์กํ ๋ก์ง์ด ์์ด์ useMemo, useCallback, React.memo๋ฑ์ ์ฌ์ฉํ๋ฉด ์คํ๋ ค ์ฑ๋ฅ์ด ์ ํ ๋๋ค๊ณ ์๊ฐํ๋๋ฐ ํน์ ๋ ๋๋ง, ์ฑ๋ฅ ๊ฐ์ ํ ๋ถ๋ถ์ด ์๋์ง ํ์ธ๋ฐ๊ณ ์ถ์ต๋๋ค.
https://velog.io/@wjdtmfgh/music-blog-%EB%B0%B0%EC%9A%B4%EC%A0%90%ED%9B%84%EA%B8%B0