티스토리 뷰

Project 댕린이집

[게시판] 게시글 수정(2)

xoo | 수진 2024. 6. 24. 22:08

이제 본격적으로 수정 기능을 구현해보겠습니다.

 

 [ 클라이언트 ] 

BoardView.js

isAuthor가 true 라면 버튼이 렌더링되고 edit() 함수를 실행하게 됩니다.

 

edit() 함수

    // 게시글 수정 페이지로 이동
    let edit = (id) => {
        console.log(id);
         navigate(`/editBoard/${id}`);
    };

 

edit 함수가 실행되면 /editBoard 페이지로 이동하게 됩니다.

 

App.js

<Route exact path='/editBoard/:id' element={<EditBoard/>}></Route>

 

App.js에 새로운 페이지를 등록해줘야겠죠.

 

EditBoard.js

더보기
import React, { useState, useEffect } from "react";
import axios from "axios";
import Nav2 from "../components/Nav2";
import { useCookies } from "react-cookie";
import { useParams, useNavigate } from "react-router-dom";

 
let EditBoard = () => {
  let { id } = useParams();

  let [formData, setFormData] = useState({
    title: "",
    content: "",
  });

  const [loading, setLoading] = useState(true);

  // 쿠키 가져오기
  let [cookies] = useCookies(["accessToken"]);
  let navigate = useNavigate();

  // 서버로부터 해당 게시글 정보를 가져옴
  useEffect(() => {
    axios.get(`http://localhost:8082/api/v1/auth/n/board?id=${id}`, {
      headers: {
        Authorization: `Bearer ${cookies.accessToken}`,
      },
    })
      .then((res) => {
        const board = res.data;
        console.log(board);
        setFormData({
          title: board.title || "",
          content: board.content || "",
        });
        setLoading(false);
      })
      .catch((error) => {
        console.error("Error: ", error);
        setLoading(false);
      });
  }, [id, cookies.accessToken]);

  let handleChange = (e) => {
    const { name, value } = e.target;
    setFormData((prevFormData) => ({
        ...prevFormData,
        [name]: value,
      }));
  };

  let handleSubmit = (e) => {
    e.preventDefault();
    // 수정된 게시글을 서버에 보냄
    axios
      .put(
        `http://localhost:8082/api/v1/auth/n/updateBoard?id=${id}`, formData, {
          headers: {
            Authorization: `Bearer ${cookies.accessToken}`,
          },
        }
      )
      .then((res) => {
        console.log("게시글이 성공적으로 수정되었습니다:", res.data);
        alert("게시글이 성공적으로 수정되었습니다!")
        navigate("/board");
      })
      .catch((error) => {
        console.error("Error: ", error);
      });
  };

  const { title, content } = formData;

  if (loading) {
    return <div>Loading...</div>;
  }

  return (
    <>
      <div>
        <Nav2 />
      </div>
      <h3 style={{ textAlign: "center", marginTop: "20px" }}>
        <strong>📝글 수정하기</strong>
      </h3>

      <div className="board-form-container">
        <form className="board-form" onSubmit={handleSubmit}>
          <div className="form-group mb-3">
            <div className="input-group flex-nowrap input-group-lg">
              <span className="input-group-text" id="addon-wrapping">
                제목
              </span>
              <input
                type="text"
                className="form-control"
                name="title"
                value={title}
                onChange={handleChange}
                required
              />
            </div>
          </div>
          <div className="form-group mb-3">
            <div className="input-group input-group-lg">
              <span className="input-group-text">내용</span>
              <textarea
                className="form-control"
                rows="3"
                name="content"
                value={content}
                onChange={handleChange}
                style={{ resize: "none", fontSize: "15px" }}
                required
              />
            </div>
          </div>
          <div className="form-group d-grid gap-2 d-md-flex justify-content-md-end">
            <div className="form-group button-group">
              <button type="submit" className="saveBtn">
                수정하기
              </button>
              <button
                type="button"
                className="listBtn"
                onClick={() => (window.location.href = "/Board")}
              >
                취소하기
              </button>
            </div>
          </div>
        </form>
      </div>
    </>
  );
};

export default EditBoard;
let [formData, setFormData] = useState({ title: "", content: "" });
let [loading, setLoading] = useState(true);
let [cookies] = useCookies(["accessToken"]);
  • useState를 사용해 formData와 loading 상태를 설정합니다.
  • useCookies를 사용해 accessToken 쿠키를 가져옵니다.
useEffect(() => {
  axios.get(`http://localhost:8082/api/v1/auth/n/board?id=${id}`, {
    headers: { Authorization: `Bearer ${cookies.accessToken}` },
  })
  .then((res) => {
    const { board } = res.data;
    setFormData({ title: board.title || "", content: board.content || "" });
    setLoading(false);
  })
  .catch((error) => {
    console.error("Error: ", error);
    setLoading(false);
  });
}, [id, cookies.accessToken]);
  • 컴포넌트가 마운트될 때, 서버에서 게시글 정보를 가져와 formData에 설정합니다.
  • 요청이 완료되면 loading 상태를 false로 설정합니다.

let handleChange = (e) => {
  const { name, value } = e.target;
  setFormData((prevFormData) => ({ ...prevFormData, [name]: value }));
};

 

입력 필드가 변경될 때마다 formData 상태를 업데이트합니다.

let handleSubmit = (e) => {
  e.preventDefault();
  axios.post(`http://localhost:8082/api/v1/auth/n/updateBoard?id=${id}`, formData, {
    headers: { Authorization: `Bearer ${cookies.accessToken}` },
  })
  .then((res) => {
    alert("게시글이 성공적으로 수정되었습니다!");
    navigate("/board");
  })
  .catch((error) => {
    console.error("Error: ", error);
  });
};
  • 폼이 제출될 때 수정된 게시글 데이터를 서버에 보냅니다.
  • 수정이 성공하면 게시글 목록 페이지로 이동합니다.

 

 

 

 [ 서버 ] 

Entity DTO Repository Mapper 는 추가/수정 사항이 없습니다.

 

BoardController.java

	@PutMapping("/updateBoard")
	public BoardDTO updateBoard(@RequestParam(name = "id") Long id, @RequestBody BoardDTO boardDTO) {
		// 게시글 ID에 해당하는 게시물을 찾아옴
		return boardService.updateBoard(id, boardDTO);
	}

 

 

BoardService.java

	public BoardDTO updateBoard(Long id, BoardDTO boardDTO) {
		BoardEntity board = boardRepository.findById(id)
				.orElseThrow(() -> new IllegalArgumentException("Invalid board ID: " + id));

		board.setTitle(boardDTO.getTitle());
		board.setContent(boardDTO.getContent());
		boardRepository.save(board);

		return boardMapper.instance.boardToDTO(board);
	}
  • findById()를 통해주어진 id로 게시글을 조회하고, 만약 게시글이 존재하지 않으면 예외를 던집니다.
  • 요청받은 boardDTO에서 새로운 제목과 내용을 가져와서 BoardEntity를 업데이트 합니다.
  • 그리고 다시 save() 메서드로 수정된 게시글을 DB에 저장합니다.
  • 업데이트 된 Entity를 DTO로 변환하여 반환해줍니다.

 

 

 

💻 [ 결과 ]  

먼저 수정할 글을 하나 등록해놓고

작성자와 로그인한 사용자가 동일하기 떄문에 수정 버튼이 보이게 되고

수정 버튼을 누르면

 

수정하기 화면이 뜨는데…

해당 글 제목과 내용이 렌더링 안되는 이슈가 존재합니다. 

 

어찌 됐든, 수정할 내용을 작성하고 수정하기 버튼을 누르면

성공적으로 수정되었다는 콘솔이 찍히고

 

글 목록을 확인해보면 수정된 글제목으로 렌더링 됩니다.

 

글 내용도 잘 수정되어 있습니다.

 

 

수정 기능 자체는 잘 되는데

수정하기 페이지로 렌더링 되었을 때, 기존의 글 제목과 내용들이 렌더링 되도록 하는 작업이 필요합니다.

 

 


 

 

💣 [ 트러블 슈팅 ] 수정하기 페이지로 렌더링 되었을 때, 기존의 글 제목과 내용들이 렌더링 되지 않는 이슈

문제

수정하기 페이지로 이동했을 때, 해당 id의 글의 제목과 내용이 그대로 렌더링 되는 것을 원했는데…그냥 글작성과 같은 빈페이지가 렌더링 되는 문제점이 있었습니다.

 

흐름

흐름을 다시 한번 살펴보자면

  1. 수정하기 페이지로 이동
    axios get 요청을 /board 로 하게 됩니다.

    게시글 목록과 상세보기에서 사용했던 /board get 컨트롤러입니다.
    여기에서 해당 id를 받아 상세 정보를 그대로 반환하게 됩니다.

  2. 수정하기 버튼 클릭 -> 수정 기능 실행
    수정하기 버튼을 클릭하면 axios put 요청을 /updateBoard 로 하게 됩니다.

    서버에서 수정 기능을 하는 /updateBoard put 컨트롤러가 받게 됩니다.

 

원인

흐름을 다시 한 번 파악한 후, 서버에서 해당 id를 잘 가져오는지 확인했습니다.

수정하기 페이지로 이동했을 때, 해당 글의 id 값을 잘 가져오고

 

id값이 들어왔기 때문에 else 문으로 가게 됩니다.

서버 쪽의 로직에는 문제가 없는 것을 확인하고 클라이언트 쪽을 살펴 보기로 합니다.

그리고 클라이언트 측 코드를 살펴보다가 아주 간단한 실수를 발견했습니다. 😓

 

const board = res.data; 라고 작성했기 때문에 데이터 구조가 달라서였기 때문입니다.

이 경우, res.data 객체 전체를 board 변수에 할당합니다. 이후에 board 변수를 통해 해당 객체의 속성에 접근할 때는 board 변수를 사용합니다.

게시글의 정보는 res.data.board에 있습니다. 그러나 const board = res.data;를 사용하면 board 변수에는 res.data 객체 전체가 할당되기 때문에, board.title 또는 board.content로 접근할 수 없게 됩니다.

 

해결

const { board } = res.data; 으로 수정해주었습니다.

객체 분해(구조 분해)를 사용하여 res.data에서 직접 board 속성을 추출하여 board 변수에 할당합니다. 이후에 board 변수를 통해 바로 해당 객체의 속성에 접근할 수 있습니다.

 

결과

수정 페이지로 이동했을 때, 해당 글의 기존 데이터가 그대로 가져와져 잘 보이는 모습입니다!

 

그 상태에서 글 수정이 자유자재로 가능하구요.

 

글을 추가한 뒤, 수정하기 버튼을 눌러보면 성공적으로 되었다고 뜹니다.

콘솔창을 확인해보면, 수정한 제목과 내용들이 그대로 저장되어 출력됩니다.

 

게시글 목록을 보니 잘 수정되어 있네요.

 

마찬가지로 잘 수정되어 있습니다!

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함