수정/삭제는 게시글을 작성한 사용자만 접근이 가능하게 한다. 그러기 위해서는 이전에 만든 AuthContext를 사용한다.
또한, axios요청에 headers: { Authorization: `Bearer ${token}` }로 인증된 사용자라는 것을 증명하게 한다.
| 게시글 수정 페이지 작성
이전에 작성한 게시글을 불러와 수정이 가능하게 하기 위해 새로운 파일을 만들어 작성한다.
frontend/src/pages/EditPostPage.js
import React, { useState, useEffect, useContext } from 'react';
import axios from 'axios';
import { useParams, useNavigate } from 'react-router-dom';
import { AuthContext } from '../context/AuthContext';
const EditPostPage = () => {
const { id } = useParams(); // 게시글 id 파라미터
const navigate = useNavigate();
const { user } = useContext(AuthContext);
const [post, setPost] = useState({ title: '', content: '' });
const [message, setMessage] = useState('');
// 1️⃣ 기존 게시글 불러오기
useEffect(() => {
const fetchPost = async () => {
try {
const res = await axios.get(`http://localhost:5000/api/posts/${id}`);
if (res.data.author._id !== user._id) {
setMessage('자신의 게시글만 수정할 수 있습니다.');
} else {
setPost({ title: res.data.title, content: res.data.content });
}
} catch (err) {
console.error(err);
setMessage('게시글 정보를 불러오지 못했습니다.');
}
};
fetchPost();
}, [id, user]);
// 2️⃣ 입력값 변경 처리
const handleChange = (e) => {
setPost({ ...post, [e.target.name]: e.target.value });
};
// 3️⃣ 게시글 수정 요청
const handleSubmit = async (e) => {
e.preventDefault();
try {
const token = localStorage.getItem('token');
await axios.put(
`http://localhost:5000/api/posts/${id}`,
post,
{ headers: { Authorization: `Bearer ${token}` } }
);
navigate(`/posts/${id}`);
} catch (err) {
console.error(err);
setMessage('수정 실패');
}
};
return (
<div>
<h2>게시글 수정 ✏️</h2>
<form onSubmit={handleSubmit}>
<input
type="text"
name="title"
value={post.title}
onChange={handleChange}
placeholder="제목"
required
/>
<br />
<textarea
name="content"
value={post.content}
onChange={handleChange}
placeholder="내용"
required
/>
<br />
<button type="submit">수정 완료</button>
</form>
{message && <p>{message}</p>}
</div>
);
};
export default EditPostPage;
/ useParams() : URL에서 게시글 ID를 추출 ( /posts/edit/:id )
/ useEffect() : 마운트 시 게시글 내용 불러옴
/ axios.put() : 수정된 내용을 서버에 전송
/ user._id !== author._id : 다른 사용자가 해당 게시글을 수정하지 못하도록 제한
/ Authorization 헤더 : 로그인한 사용자임을 인증하기 위해 토큰 전송
| 수정 라우터 추가
frontend/src/routes/postRoutes.js
<Route
path="/posts/edit/:id"
element={
<ProtectedRoute>
<EditPostPage />
</ProtectedRoute>
}
/>
| 삭제 추가
기존의 PostDetailPage.js에 수정/삭제 버튼을 만들고 수정버튼을 누르면 위에서 만든 EditPostPage로 이동하게 하고 삭제를 누르면 해당 게시글이 삭제하게 한다.
frontend/src/pages/PostDetailPage.js
import React, { useEffect, useState, useContext } from 'react';
import { useParams, Link, useNavigate } from 'react-router-dom';
import axios from 'axios';
import { AuthContext } from '../context/AuthContext';
const PostDetailPage = () => {
const { id } = useParams(); // URL 파라미터에서 post ID 추출
const { user } = useContext(AuthContext);
const [post, setPost] = useState(null);
const [loading, setLoading] = useState(true);
const [ message, setMessage ] = useState('');
const navigate = useNavigate();
// 게시글 불러오기
useEffect(() => {
const fetchPost = async () => {
try {
const res = await axios.get(`http://localhost:5000/api/posts/${id}`);
setPost(res.data);
} catch (err) {
console.error('게시글 조회 실패:', err);
} finally {
setLoading(false);
}
};
fetchPost();
}, [id]);
// 2️⃣ 삭제 요청
const handleDelete = async () => {
if (!window.confirm('정말 삭제하시겠습니까?')) return;
try {
const token = localStorage.getItem('token');
await axios.delete(`http://localhost:5000/api/posts/${id}`, {
headers: { Authorization: `Bearer ${token}` },
});
navigate('/posts');
} catch (err) {
console.error(err);
setMessage('삭제 실패');
}
};
if (loading) return <p>로딩 중...</p>;
if (!post) return <p>게시글을 찾을 수 없습니다.</p>;
const isAuthor = user && post.author._id === user._id;
return (
<div>
<h2>{post.title}</h2>
<p><strong>작성자:</strong> {post.author.username}</p>
<p><strong>작성일:</strong> {new Date(post.createdAt).toLocaleDateString()}</p>
<hr />
<p>{post.content}</p>
<br />
{isAuthor && (
<div>
<Link to={`/posts/edit/${post._id}`}>
<button>수정</button>
</Link>
<button onClick={handleDelete}>삭제</button>
</div>
)}
{message && <p>{message}</p>}
<br />
<Link to="/posts"><button>목록</button></Link>
</div>
);
};
export default PostDetailPage;
글의 내용은 누구나 볼 수 있지만 수정/삭제 버튼은 글작성자만 확인 할 수 있다.
아직 레이아웃 구조가 완벽하지 않고 보기 좋게 꾸미기 전이라서 목록 버튼의 위치는 일단 넘어가겠다.
삭제를 누르면 확인 창이 뜨고 확인을 누르면 해당 글이 완전히 삭제된다.
'STUDY > Project' 카테고리의 다른 글
React프로젝트에 Tailwind CSS 설치 및 설정 (0) | 2025.05.08 |
---|---|
마무리 작업 - HomePage, 이동버튼 추가 (0) | 2025.05.08 |
게시글 수정, 삭제 기능 추가하기 - postController (0) | 2025.05.07 |
프론트엔드 기능별 라우터 분리 - routes/ (0) | 2025.05.06 |
게시판 페이지 작성 - PostListPage, PostDetailPage, CreatePostPage (0) | 2025.05.06 |