우선 좋은 영상 감사합니다. 의미있는 경험이 되었던 것 같아요. 거의 다 만들었는데 정말 최종적으로 MainPage안에서 2가지 문제가 생겼습니다.
1. 마지막 게시물까지 확인해도 더보기가 사라지지 않습니다.
2. 새로고침을 하면 로그아웃은 되지 않으나 순간적으로 token을 읽지 못하고 useEffect에 의해 로그인 페이지로 이동하는 것 같습니다.
MainPage.js
import React, { useState, useEffect } from 'react'
import axios from 'axios'
import List from './Post/List'
import '../Style/MainPage.css'
import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
function MainPage() {
const [sort, setSort] = useState("최신순")
const [postList, setPostList] = useState([])
const [searchTerm, setSearchTerm] = useState("")
const [skip, setSkip] = useState(0)
const [loadMore, setLoadMore] = useState(true)
const navigate = useNavigate()
const user = useSelector(state=>state.user)
useEffect(()=>{
console.log(user.accessToken)
if(!user.accessToken){
alert("로그인된 회원만 이용할 수 있습니다.")
navigate('/login')
}
console.log(user.accessToken)
}, [])
const getLoadMore = () => {
let body = {
sort: sort,
searchTerm: searchTerm,
skip: skip
}
axios.post('/api/post/list', body)
.then(res => {
if (res.data.success) {
setPostList([...postList, ...res.data.postList])
setSkip(skip + res.data.postList.length)
if (res.data.postList.lengh < 3) {
setLoadMore(false)
}
}
}).catch(err => {
console.log(err)
})
}
const getPostList = () => {
setSkip(0)
let body = {
sort: sort,
searchTerm: searchTerm,
skip: 0
}
axios.post('/api/post/list', body)
.then(res => {
setPostList([...res.data.postList])
setSkip(res.data.postList.length)
if (res.data.postList.lengh < 3) {
setLoadMore(false)
console.log(loadMore)
}
}).catch(err => {
console.log(err)
})
}
useEffect(() => {
getPostList()
}, [sort])
const Search = (e) => {
getPostList()
}
return (
<div>
<div className='SearchAndArrange'>
<button onClick={() => setSort("최신순")}>최신순</button>
<button style={{ marginLeft: "5px", marginRight: "20px" }} onClick={() => setSort("인기순")}>인기순</button>
<input style={{ marginRight: "5px" }} placeholder='제목 또는 내용' type="text" value={searchTerm} onChange={e => setSearchTerm(e.target.value)} />
<button onClick={(e) => Search(e)}>검색</button>
<button style={{marginLeft: "10px"}} onClick={()=>navigate('/upload')}>게시글 작성</button>
</div>
<List postList={postList} />
{loadMore && (<button className='SeeMore' onClick={() => getLoadMore()}>더 보기</button>)}
</div>
)
}
export default MainPage
서버쪽 post.js
const express = require('express')
const router = express.Router()
const multer = require('multer')
const { Post } = require('../models/post.js')
const { Counter } = require('../models/counter.js')
const { User } = require("../models/user")
const { Router } = require('express')
router.post('/submit', (req, res) => { //게시글 작성 기능
let temp = {
title: req.body.title,
content: req.body.content,
image: req.body.image,
}
Counter.findOne({ name: 'counter' }).exec().then(counter => {
temp.postNum = counter.postNum //counter의 게시물 번호를 지정해 줌.
User.findOne({ uid: req.body.uid }).exec().then(userInfo => { //요청된 uid와 일치하는 user를 찾아서
temp.author = userInfo._id // 해당 user의 Id번호를 권한번호로 지정한 뒤
const CommunityPost = new Post(temp) //새로운 포스트모델을 생성하여 요청된 정보와 함께 넘겨줌.
CommunityPost.save().then(() => {
Counter.updateOne({ name: "counter" }, { $inc: { postNum: 1 } }) //counter의 게시물 번호를 1증가
.then(() => {
res.status(200).json({ success: true })
})
})
})
}).catch(err => {
err.status(400).json({ success: false })
})
})
router.post('/list', (req, res) => {
let sort = {}
if(req.body.sort ==="최신순"){
sort.createdAt = -1
}else{
sort.repleNum = -1
}
Post.find({$or : [{title: {$regex: req.body.searchTerm}}, {content: {$regex: req.body.searchTerm}}]})
.populate("author")
.sort(sort)
.skip(req.body.skip) //
.limit(3)
.exec()
.then(doc => { //populate는 주어진 정보를 통해 다른 document의 객체를 불러옴. 여기서는 author를 통해 user를 참조하여 Id를 가지고 옴.
res.status(200).json({ success: true, postList: doc })
}).catch(err => {
res.status(400).json({ success: false })
})
})
router.post('/detail', (req, res) => {
Post.findOne({ postNum: Number(req.body.postNum) }).populate("author").exec() //요청된 게시물 번호가 일치하는 post를 찾음
.then(doc => {
res.status(200).json({ success: true, post: doc }) //post라는 이름으로 해당 post 정보를 전송함.
}).catch(err => {
res.status(400).json({ success: false })
})
})
router.post('/edit', (req, res) => {
console.log(req.body)
let temp = {
title: req.body.title,
content: req.body.content,
}
Post.updateOne({ postNum: Number(req.body.postNum) }, { $set: temp }).exec() //게시물번호를 넘겨받아 해당 게시물을 temp로 업데이트
.then(() => {
console.log("수정성공")
res.status(200).json({ success: true })
}).catch(err => {
console.log("수정실패")
err.status(400).json({ success: false })
})
})
router.post('/delete', (req, res) => {
Post.deleteOne({ postNum: Number(req.body.postNum) }).exec() //전달받은 게시물 번호를 찾아서 삭제해 줌.
.then(doc => {
res.status(200).json({ success: true })
}).catch(err => {
console.log(err)
res.status(400).json({ success: false })
})
})
const storage = multer.diskStorage({ //multer를 통해 전달받은 데이터를 파일 디스크에 저장
destination: (req, file, cb) => { //저장할 경로를 지정
cb(null, 'image')
},
filename: (req, file, cb) => { //저장할 파일의 이름 지정
cb(null, Date.now() + '-' + file.originalname)
}
})
const upload = multer({ storage: storage }).single('image')
router.post('/image/upload', (req, res) => {
upload(req, res, (err) => {
if (err) {
res.status(400).json({ success: false })
}
else {
res.status(200).json({ success: true, filepath: req.file.path })
}
})
})
module.exports = router