728x90
<게시판 기능>
- pagination 기능 -> 한 페이지당 글의 개수 설정할 수 있는 기능
- 수정, 삭제
//App.js
import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Board from "./components/Board";
import PostForm from "./components/PostForm";
import BoardDetail from "./components/BoardDetail";
import PostEditForm from "./components/PostEditForm";
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Board />} />
<Route path="/board/:id" element={<BoardDetail />} />
<Route path="/postform" element={<PostForm />} />
<Route path="/edit/:id" element={<PostEditForm />} />
</Routes>
</Router>
);
}
export default App;
총 네 개의 페이지로 구성되어있습니다.
- Board.js
- BoardDetail.js
- PostForm.js
- PostEditForm.js
Board.js
-> 게시판 메인 화면
- 글의 목록을 보여줌 ➔ 글의 제목을 누르면 해당 글을 볼 수 있는 페이지로 랜더링
- 한 페이지당 노출할 글의 수를 설정할 수 있고 페이지를 바꿀 수 있는 기능이 있음.
- 글을 쓸 수 있는 버튼
//Board.js
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import "../css/Board_style.css";
const Board = () => {
const navigate = useNavigate();
const [boardList, setBoardList] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [postsPerPage, setPostsPerPage] = useState(10); // Number of posts per page, default: 5
const [totalPages, setTotalPages] = useState(1); // Total number of pages
useEffect(() => {
getBoardList();
}, [currentPage, postsPerPage]);
const getBoardList = async () => {
try {
const response = await axios.get("http://localhost:8080/board/me");
setBoardList(response.data);
setTotalPages(Math.ceil(response.data.length / postsPerPage));
} catch (error) {
console.error("불러오지 못함", error);
}
};
const indexOfLastPost = currentPage * postsPerPage;
const indexOfFirstPost = indexOfLastPost - postsPerPage;
const currentPosts = boardList.slice(indexOfFirstPost, indexOfLastPost);
const paginate = (pageNumber) => setCurrentPage(pageNumber);
const handlePostsPerPage = (e) => {
setPostsPerPage(parseInt(e.target.value));
setCurrentPage(1);
};
const Post = () => {
navigate("/postform");
};
return (
<div className="board-container">
<h1 className="board-title">게시판</h1>
<div className="board-button">
<button onClick={Post}>글쓰기</button>
</div>
<br />
<ul className="board-posts">
{currentPosts.map((board) => (
<li key={board.id} className="board-post-item">
<Link to={`/board/${board.id}`}>{board.title}</Link>
<span>작성자: {board.writer}</span>
<span> | 작성 시간: {board.writingTime}</span>
</li>
))}
</ul>
<div className="board-posts-per-page">
<label>
게시물 수:{" "}
<select value={postsPerPage} onChange={handlePostsPerPage}>
<option value={10}>10개</option>
<option value={20}>20개</option>
<option value={30}>30개</option>
</select>
</label>
</div>
<div className="board-pagination">
{[...Array(totalPages).keys()].map((number) => (
<button
key={number + 1}
className={currentPage === number + 1 ? "selected" : ""}
onClick={() => paginate(number + 1)}
>
{number + 1}
</button>
))}
</div>
</div>
);
};
export default Board;
<글쓰기 버튼을 누를 시>
//PostForm.js
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import "../css/PostForm_style.css";
const PostForm = ({ addPost }) => {
const navigate = useNavigate();
const [writer, setWriter] = useState("");
const [title, setTitle] = useState("");
const [body, setBody] = useState("");
const savePost = async (e) => {
try {
const response = await axios.post(
"http://localhost:8080/board",
{
writer: writer,
title: title,
body: body,
},
{
headers: {
"Content-Type": "application/json",
},
}
);
if (response.status === 200) {
alert("게시물이 등록되었습니다.");
navigate("/");
} else {
throw new Error("게시물 등록 실패");
}
} catch (error) {
console.error("Error:", error);
alert("게시물 등록에 실패했습니다.");
}
};
const backToBoard = () => {
navigate("/");
};
return (
<div className="container">
<div className="input-group">
<h2 style={{ textAlign: "center" }}>글쓰기</h2>
<span>제목</span>
<input
type="text"
placeholder="제목"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
</div>
<div className="input-group">
<span>작성자</span>
<input
type="text"
placeholder="작성자"
value={writer}
onChange={(e) => setWriter(e.target.value)}
/>
</div>
<textarea
placeholder="내용"
cols="100"
rows="10"
value={body}
onChange={(e) => setBody(e.target.value)}
/>
<div className="button-group">
<button onClick={savePost}>저장</button>
<button onClick={backToBoard}>취소</button>
</div>
</div>
);
};
export default PostForm;
- 저장 버튼 누를 시 게시판 메인화면(Board.js)로 다시 렌더링
- 취소 버튼 누를 시 게시판 메인화면(Board.js)로 다시 렌더링
BoardDetail.js
-> 글의 세부사항을 볼 수 있는 페이지
- 수정버튼-> 새로운 페이지(PostEditForm.js)로 렌더링
- 삭제할 수 있는 기능이 있음
- 게시판 목록으로 다시 돌아 갈 수 있는 기능이 있음 (Board.js 페이지 렌더링)
//BoardDetail.js
import React, { useEffect, useState } from "react";
import { useParams, useNavigate } from "react-router-dom";
import axios from "axios";
import "../css/BoardDetail_style.css";
const BoardDetail = () => {
const { id } = useParams();
const navigate = useNavigate();
const [board, setBoard] = useState({});
const getBoard = async () => {
try {
const response = await axios.get(
`http://localhost:8080/board?writingId=${id}`
);
setBoard(response.data);
} catch (error) {
console.error("불러오지 못함", error);
}
};
useEffect(() => {
getBoard();
}, [id]);
const moveToEdit = () => {
navigate("/edit/" + id);
};
const deletePost = async () => {
if (window.confirm("게시글을 삭제하시겠습니까?")) {
await axios.delete(`http://localhost:8080/board/${id}`);
alert("삭제되었습니다.");
navigate("/");
}
};
const moveToBoard = () => {
navigate("/");
};
return (
<div className="board-detail-container">
<div className="board-detail-content">
<h2 className="board-detail-title">{board.title}</h2>
<div className="board-detail-info">
<h5>작성자 : {board.writer}</h5>
<p style={{ fontSize: "12px", color: "gray" }}>{board.writingTime}</p>
</div>
<hr />
<p className="board-detail-body">{board.body}</p>
<hr />
<div className="board-detail-button-group">
<button onClick={moveToEdit}>수정</button>
<button onClick={deletePost}>삭제</button>
<button onClick={moveToBoard}>목록</button>
</div>
</div>
</div>
);
};
export default BoardDetail;
<삭제 버튼 클릭시>
PostEditForm.js
-> 글을 수정할 수 있는 페이지
//PostEditForm.js
import React, { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import axios from "axios";
import "../css/PostForm_style.css";
const PostEditForm = () => {
const navigate = useNavigate();
const { id } = useParams();
const [post, setPost] = useState({});
const { writer, title, body } = post;
const onChange = (event) => {
const { value, name } = event.target;
setPost((prevPost) => ({
...prevPost,
[name]: value,
}));
};
const getPost = async () => {
try {
const response = await axios.get(
`http://localhost:8080/board?writingId=${id}`
);
setPost(response.data);
} catch (error) {
console.error("불러오지 못함", error);
}
};
const backToPost = () => {
navigate("/board/" + id);
};
const updatePost = async () => {
try {
const response = await axios.put(
`http://localhost:8080/board/${id}`,
post
);
console.log(post);
if (response.status === 200) {
alert("수정되었습니다.");
navigate("/board/" + id);
} else {
throw new Error("게시물 수정 실패");
}
} catch (error) {
console.error("Error updating board:", error);
alert("게시물 수정에 실패했습니다.");
}
};
useEffect(() => {
getPost();
}, []);
return (
<div>
<h2 class style={{ textAlign: "center" }}>
글 수정하기
</h2>
<div className="container">
<div className="input-group">
<span>제목</span>
<input
type="text"
name="title"
placeholder="제목"
value={title}
onChange={onChange}
/>
<span> 작성자</span>
<input
type="text"
name="writer"
placeholder="작성자"
value={writer}
readOnly={true}
/>
<br />
<br />
<textarea
placeholder="내용"
name="body"
cols="100"
rows="30"
value={body}
onChange={onChange}
/>
<br />
<div className="button-group">
<button onClick={updatePost}>수정완료</button>
<button onClick={backToPost}>수정취소</button>
</div>
</div>
</div>
</div>
);
};
export default PostEditForm;
수정이 가능하게 하려면 <textarea>에 name 필드를 무조건 작성해야 한다...!!
수정완료 및 수정취소 버튼을 누르면 글의 상세정보를 보여주는 페이지(PostDetail.js)로 렌더링 됨.
게시판 프로젝트를 하면서 API 참조하는 법을 확실하게 배웠다.
API 참조 방법을 배우고자 하는 분들에게 아주 간단하고 배우기 좋은 프로젝트 주제라고 생각한다 !
참고 : https://onethejay.tistory.com/191
728x90
'웹 프로그래밍' 카테고리의 다른 글
[GCP] GCS(Google Cloud Storage) Bucket 버킷 사용하기 + spring boot 에서 사용하기 (0) | 2024.06.29 |
---|---|
[GCP] GCP VM에 Docker 이용해서 Spring Boot와 React 배포하기 (1) | 2024.06.02 |
GCP 가상 머신 생성 및 APACHE 서버 배포(feat.vscode로 ssh) (0) | 2024.03.12 |
scp : 로컬 환경에서 원격 서버로 파일 보내기 [ssh 인증키 관련 오류 해결] (0) | 2024.03.12 |