수정 & 삭제 기능

세인트킴·2024년 5월 22일

hcmc

목록 보기
5/10

리스트 내역 불러오기

// 내역 불러오기
router.get("/money", async (req, res) => {
  try {
    const wallet = await Wallet.find().sort({ createdAt: -1 });
    wallet.map((item => ({
      id: item._id,
      date: item.date,
      title: item.title,
      category: item.category,
      amount: item.amount,
      tag: item.tag
    })))
    res.json(wallet);
  } catch(err) {
  	console.error(err);
  }
});

원래는 위의 코드를 작성했지만 wallet.map()를 안해도 되는거 아닌가 싶어서 지워봤는데, 역시 안해도 되는 거였다.. 그동안 res.json()에서 데이터를 전달해주는 거였는데 몰랐지만 알게 되는 계기가 된거 같다.

최근 게시글 순서로 불러오기

// 내역 불러오기
router.get("/money", async (req, res) => {
  try {
    const wallet = await Wallet.find().sort({ createdAt: -1 });
    res.json(wallet);
  } catch(err) {
  	console.error(err);
  }
});

AccountList에 추가된 rows, columns들이 새로운 게시물일 수록 뒷 페이지로 이동하기 때문에 이를 해결하기 위해서 find()뒤에 sort({ createdAt: -1 })을 추가해서 가장 최근에 만들어진 게시물을 1번 row에 나타나도록 만들었다.

그리고 추가한 리스트를 수정하기 위해서 클릭한 게시물의 ObjectId를 알아야 한다. 이를 위해 row를 클릭하면, ObjectId를 나오게 하는 로직을 작성했다.

클릭한 게시물의 ObjectId 가져오기

const mongoose = require('mongoose');

router.post("/money/:id", async(req, res) => {
  try {
    const { id } = req.params;
    const ObjectId = new mongoose.Types.ObjectId(id);
    const wallet = await Wallet.findById(ObjectId);
    
    console.log(wallet);
    res.json(wallet);
  } catch(err) {
  	console.error(err);
  }
});

기존의 MongoDB를 사용할 때는 { id: new ObjectId(id) };이런 방법으로 ObjectId를 추출했다. 하지만 mongoose를 사용하면 더 간편한 방법으로 ObjectId를 추출할 수 있다. mongoose.Types.ObjectId는 스키마를 만들 때 설정해놓은 데이터 타입을 불러오는 방법이랑 동일하다. 백엔드에서 이런 로직을 작성해주고 프론트엔드로 넘어와서 <TableRow onClick={() => handleRowClick(row._id)}> 함수를 작성해준다. 이 함수를 실행하면 콘솔에 ObjectId가 출력된다.

const handleRowClick = async (id) => {
  try {
    const response = await axios.post(`http://localhost:4000/wallet/money/${id}`, { id },
                                      { headers: "Content-Type": "application/json" }
    );
    console.log(response.data);
  } catch(err) {
  	console.error(err);
  }
}

<TableBody>
  {rows
  .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
  .map((row) => {
    return (
      // row._id: ObjectId이기 때문에 이걸 클릭하면 ObjectId가 눌려지도록 하기
      <TableRow hover role="checkbox" tabIndex={-1} key={row._id} onClick={() => handleRowClick(row._id)} >
        {columns.map((column) => {
          const value = row[column.id];
          return (
            <TableCell key={column.id} align={column.align}>
              {value}
            </TableCell>
          );
        })}
      </TableRow>
    );
  })}
</TableBody>

위의 .slice()는 페이지네이션이므로 짧게 설명하자면 page * rowsPerPage는 시작 인덱스, page * rowsPerPage + rowsPerPage는 끝 인덱스로서, 시작 인덱스부터 끝 인덱스까지의 row를 보여주도록 하는 것이다.

그리고 map()메소드를 사용할 때 map()의 키 값으로 row._id를 사용하기 때문에 클릭을 하면 row._id를 추출하는 방법이 가능할 것이라고 생각했다.

이제 행을 만들었으니 행을 띄워줄 열도 만들면 된다. const value = row[column.id] 에서 열의 id를 이용해 인덱스 번호(id)에 해당하는 값을 만든다.
예를 들어 row = ['커피', '우유']가 있다면 커피: 0, 우유: 1id를 가진다.

클릭시에 window창 띄워서 데이터 삭제하기

이렇게 해서 클릭할 시 그에 맞는 ObjectId를 추출하고 클릭할 시 window()가 나와서 삭제할 지 정하는 handleDelteWindow(id)handleDeleteWindow()에 작성해준다.

const handleRowClick = async (id) => {
  try {
    const response = await axios.post(`http://localhost:4000/wallet/money/${id}`, { id },
                                      { headers: "Content-Type": "application/json" }
    );
    console.log(response.data);
    handleDeleteWindow(id);
  } catch(err) {
  	console.error(err);
  }
}

// 삭제창 띄우기
const handleDeleteWindow = (id) => {
  if (window.confirm("삭제하시겠습니까?")) {
  	handleDeleteClick(id);
  }
}
// 데이터 삭제
const handleDeleteClick = async (id) => {
  try {
  	const response = await axios.post(`/http://localhost/wallet/money/delete/${id}`);
  	console.log(response.data);
  	window.location.reload();
  } catch(err) {
  	console.error(err);
  }
};

현재 삭제하고 나면 window.location.reload();가 떠야 하는데, 아마도 리액트에서 상태 관리로 useState()를 사용하지 않아서 데이터가 삭제되도 새로고침 되지 않는데 이걸 해결해야 할 것 같다. 이를 해결하기 위해 백엔드에서 응답으로 res.redirect('/') 기본 페이지 로직으로 재연결 해주는 것도 작성했지만 동작하지 않는 버그가 생겼다.

여기서 작성한 이 코드를 useEffect()에 넣어서 한번에 동작하도록 하고 싶은데 useEffect()에 넣으면 제일 처음 진행되야 할 handleRowClick()가 찾지 못한다고 한다.
이 역시 해결하기 위해 밑에 함수들을 호출하는 방법을 통해 문제를 해결해야겠다..(아직 해결 못함)

백엔드 데이터 삭제 로직

router.post("/money/delete/:id", async (req, res) => {
  try {
  	const { id } = req.params;
    const ObjectId = new mongoose.Types.ObjectId(id);
    cont wallet = await Wallet.findById(ObjectId);
    
    console.log("지운 내역: \n", wallet);
    // 찾은 :id삭제
    wallet.deleteOne();
    res.redirect('/');
  } catch(err) {
  	console.error(err);
  }
})

{ id } = req.params를 만들고 wallet 상수에 ObjectId를 할당해서 wallet.deleteOne()를 해준 뒤 res.redirect('/')해주는 간단한 로직이다. 그런데 위에서 설명했듯, 삭제 후 페이지 새로고침이 자동으로 되지 않는 버그가 생겼다.

진행사항과 할 것

현재까지의 진행도는 자동으로 새로고침 하도록 리스트 상태 관리를 해준 뒤, 수직 막대 그래프를 리스트와 동기화 한 뒤, 원형 그래프도 데이터와 연동해주는 게 1순위

그리고 모달창 만들어서 수정&삭제 기능을 여기서 동작하도록 구현해야 할듯하다. 이게 안된다면 현재처럼 window()띄워서 수정 || 삭제 기능을 해야한다는 선택이 있다.

그 뒤로는 프론트엔드와 서로 파일을 합쳐서 플랜에 맞는 자유로운 소비 로직을 구현하면 된다.

시연할 때는 LiveShare를 켜서 현재 IP를 입력한 뒤, 학교 컴퓨터로 들어가거나, 배포를 하면 이번 프로젝트는 완성된다.

profile
잘하는 건 노력

0개의 댓글