
https://kangcheon.tistory.com/100
react-hook-form,react-query 사용한 몬스터도감 만들기 (1)
제목은 몬스터 도감이지만 사실상 todoList입니다.. 사실 ToDoList 정도야 기본적인 CRUD 기능만 있으면 끝이므로 react-query,react-hook-form 까지 사용하지 않아도 상관없지만... 최근 두 라이브러리를 학습
kangcheon.tistory.com
이전 글에 이어서 이번엔 수정/삭제 기능을 구현해보자
전체 코드는 이곳에서 확인 가능하다
https://github.com/kangaroo19/common_component
GitHub - kangaroo19/common_component
Contribute to kangaroo19/common_component development by creating an account on GitHub.
github.com
삭제

//monsterQuery.js
const deleteMonster = (monsterIdArr) => {
const deleteRequests = monsterIdArr.map((monsterId) => {
return axios.delete(`http://localhost:4000/monster/${monsterId}`);
});
return Promise.all(deleteRequests);
};
export const useMonsterMutationDelete = (refetch) => {
return useMutation({
mutationFn: deleteMonster,
onSuccess: () => {
alert('삭제 성공!!!!');
refetch();
},
onError: (error) => {
alert(`${error.response.status} ${error.response.data}`);
},
});
};
원래는 단건삭제 요청함수와 전체삭제 요청함수 이렇게 두개의 함수를 사용하였는데
Promise.all로 함수 마지막 부분에 병렬처리해주고 단건삭제 시 길이가 1인 배열로 인자로 받는 함수를 만들었다
//MonsterList.jsx
const { data, isLoading, refetch, isError } = useMonsterDataQuery();
// 단건 삭제
const onClickDeleteMonster = (monsterId) => {
mutate([monsterId]);
};
// 전체삭제
const onClickAllDeleteBtn = () => {
const monsterIdArr = data.data.map((item) => item.id);
mutate(monsterIdArr);
};
단건삭제는 해당 몬스터의 아이디값을 인자로 받아서 해당 몬스터만을 삭제해준다
전체삭제는 get요청 시 받아온 전체리스트들의 아이디값만을 따로 추출하여 인자로 넣어 모든 리스트를 삭제해준다
수정

import { create } from 'zustand';
export const useToggleUpdateBtn = create((set) => ({
isUpdate: false,
setIsUpdateTrue: () => {
set({ isUpdate: true });
},
setIsUpdateFalse: () => {
set({ isUpdate: false });
},
}));
우선 post요청을 보내던 같은 form 컴포넌트에서 patch 요청도 보낼 것이므로 현재 몬스터 수정 중인지에 대한 상태를 관리하기 위해 zustand를 사용하였다
- isUpdate : false => 수정 중 아님,post 요청
- isUpdate : true => 수정 중 , patch 요청
const updateMonster = (monster) => {
return axios.patch(`http://localhost:4000/monster/${monster.id}`, monster);
};
export const useMonsterMutationUpdate = (reset, refetch, setIsUpdateFalse) => {
return useMutation({
mutationFn: updateMonster,
onSuccess: () => {
alert('수정 성공!!!!');
refetch();
reset();
setIsUpdateFalse();
},
onError: (error) => {
alert(`${error.response.status} ${error.response.data}`);
},
});
};
patch 요청이 성공적으로 완료되었다면 setIsUpdateFalse 함수로 isUpdate 값을 false로 되돌려 준다
// MonsterList.jsx
const { setValue } = useFormContext();
const onClickUpdateMonster = (monster) => { // 수정
setValue('monsterName', monster.monsterName);
setValue('level', monster.level);
setValue('id', monster.id);
setIsUpdateTrue();
};
react-hook-form 의 form 필드의 값을 설정할 때 사용하는 setValue 함수를 통해 수정 버튼을 누른 해당 몬스터에 대한 정보를 저장해주고 setIsUpdateTrue 함수를 통해 isUpdate 값을 true로 바꿔주자
setValue의 첫번째 인자인 문자열은 MonsterForm에서 register 함수의 인자값과 동일해야한다는 점에 주의하자
// MonsterForm.jsx
const { isUpdate, setIsUpdateFalse } = useToggleUpdateBtn();
const isUpdateObj = {
isUpdateText: isUpdate ? '몬스터 수정' : '몬스터 등록',
mutateFn: isUpdate
? useMonsterMutationUpdate(reset, refetch, setIsUpdateFalse) // patch
: useMonsterMutationPost(reset, refetch), // post
};
// post or patch method
const handleFormButton = (data) => {
const { name, level } = data;
if (name === '' || level === '') return;
isUpdateObj.mutateFn.mutate(data);
};
수정 기능 추가에 있어서 기존 코드도 마찬가지로 수정을 하였다
isUpdateObj은 isUpdate 값에 따른 버튼에 랜더링될 텍스트, 사용할 훅이 달라지는 객체이다
원래는 각각 변수를 따로 둬서 isUpdate값에 따른 분기처리했는데 이렇게 하나의 객체로 묶는 것이 가독성이 더 좋다고 판단하여 저렇게 코드를 수정하였다
이제 기본적인 CRUD 기능은 완성되었다!!
자잘한 트러블 슈팅
- 원래는 MonsterForm 컴포넌트안에서 업데이트 요청(mutate함수) 이후 setIsUpdateFalse로 isUpdate를 false로 되돌리려 했는데 mutate 는 비동기 함수라 그런지 setIsUpdateFalse가 먼저 실행되어 isUpdate가 거짓일 때의 로직이 동작하였음 그래서 현재 코드처럼
함수를 콜백으로 넣는 이 형태가 되었습니다~ -
useMonsterMutationUpdate(reset, refetch, setIsUpdateFalse)
완료

조금 시간을 들여서 이렇게 퍼블리싱 작업까지 완료하였다
레이아웃 작업은 mui의 grid 컴포넌트를 사용하여 작업하였다
'React' 카테고리의 다른 글
컴포넌트 리팩토링 과정 (0) | 2024.05.02 |
---|---|
깃허브 페이지와 커스텀 도메인 (0) | 2024.04.03 |
react-hook-form,react-query 사용한 몬스터도감 만들기 (1) (1) | 2024.03.22 |
react-hook-form을 이용한 인풋 컴포넌트 구현 (0) | 2024.03.20 |
버튼 컴포넌트 css 파일 관리 (0) | 2024.03.12 |