728x90
어떤 고민?
✨ 이번 프로젝트 때 위키 수정을 위해 사용하는 PATCH 메서드를 위해 FormData 생성로직을 만들어야 했다.
🔖 초기 로직과 문제점
🚫 로직의 비효율성
- 우리 API는
PATCH
메서드를 통해 위키를 수정하는데, 수정 전에 퀴즈를 풀어 답변과 함께 엔드포인트가ping
인 API로GET
요청을 보내어 성공 상태 코드를 받아야PATCH
메서드를 사용 가능한 시스템이었다. (따로 알려주지 않아 직접 swagger로 박치기해서 알아냈다... 🥲) - 여하튼 이러한 과정은 다 제쳐두고
PATCH
메서드 자체만 놓고 보자면,PATCH
의 경우 변경하고 싶은 데이터만 뽑아내어FormData
에 담아 전송해야 했기 때문에 이걸 어떤식으로 만들어야 하나라는 고민이 많았다. - 또한 이미지를 넣어 보내는 경우,
image
엔드포인트 API에 먼저 보내어 알맞는URL
을 획득하여 다시 넣어줘야 하는 번거로움도 있었다.
📖 처음 생각했던 로직
// formData 상태값
const [formData, setFormData] = useState<ChangeProfilesFormData>(FORM_DATA_INIT);
// 데이터 전송 로직
const handleSaveClick = async () => {
try {
const data = new FormData();
// 이미지 처리 함수
const processImage = async () => {
if (formData.image) {
const imageData = new FormData();
imageData.append('image', formData.image);
const res = await getImageUrl(imageData as ImageData);
return res?.url || '';
}
return 'null'; // 이미지가 없을 경우 'null' 문자열 전송
};
// 변경된 필드와 데이터 처리
Object.keys(formData).forEach((key) => {
const currentValue = formData[key as keyof ChangeProfilesFormData];
const previousValue = FORM_DATA_INIT[key as keyof ChangeProfilesFormData];
if (currentValue !== previousValue && key !== 'image') {
data.append(key, currentValue as string);
}
});
// 이미지 처리 후 URL 추가
const imageUrl = await processImage();
data.append('image', imageUrl);
// 프로필 변경 요청
const res = await changeProfile(userProfile?.code, data as unknown as ChangeProfilesFormData);
setUserProfile(res);
setIsEditing(false);
resetState();
} catch (error) {
alert(error);
}
};
- 처음 생각했던 로직과 해당 로직을 작성할 때 내 생각은 이러했다.
PATCH
메서드를 보내기 위한FormData
에는 변경하고 싶은 데이터만 들어가야 한다. (기본적으로 '수정'이란 내가 원하는 데이터를 변경하되 남은 데이터는 그대로 두어야 하므로)- JS는 기본적으로 API 요청 시 보내는 데이터 객체로
new FormData()
를 제공한다. - 따라서
FORM_DATA_INIT
이라는 기본 객체 템플릿을 만들고, 이를formData
상태값의 기본값으로 설정 후, 데이터를 보낼 때마다 두 객체의value
를 비교하여 변경된 것만FormData
객체에 넣는다면 이를 구현할 수 있지 않을까?
🥲 그땐 좋다고 생각했으나 지금 생각해보면 상당히 비효율적이고 엉성하다.
- 또한
useState
를 사용하는 로직은 기본적으로 비동기이고,new FormData()
로직을 활용하는 건 분기를 설정하기에도 애매한 점이 있었다. - 또한 가장 중요했던 점은, 수정 모드로 진입 시 기존 데이터를 모두 수정할
FormData
에 기본 값으로 설정하여 변경하고 싶은 값만 변경하면서도 데이터의 상태를 확인할 수 있도록 의도했는데, 상태값이다 보니 변경하다가 취소할 시 페이지를 새로고침하지 않는 이상 그대로 데이터가 남아버린다는 점이었다. - 또한 이미지와 같은 따로 데이터를 보내고 받아와야 하는 로직도 포함되어 있다보니 데이터가 엉키는 느낌이어서 사용할 수록 이 로직은 아니라는 생각이 강하게 들었다.
📖 다시 시작된 고민과 해결
- 사실 이 로직을 고민하기 전에 그냥
formData
상태값을 직접 보내는건 안되는건가? 라는 생각도 해보았었다. - 그런데
Content-Type
을 따로 설정해주지 않았었고 지식도 별로 없었어서 무조건new FormData()
를 통해 객체를 만들어야지만 가능한건가보다.. 하고 말았었는데 😂 - 😎 멘토님께서 그냥 formData 상태값을 직접 보내는게 나을거라고 조언해주셨다..!
- 또한
PATCH
는 결국 변경을 위해 데이터를 뽑아 보내는 것이므로, 변경할 값을 제외한 다른 모든 값을 그대로 보내면 결국 변경하고 싶은 값만 바뀌는거나 다름없다는 말씀도 해주셨다. - 고 말을 들으니까 눈이 번쩍 뜨이고 답답했던 속이 시원해지는 느낌을 받았다..! 🧊🧊🧊
// formData 전송 로직
const handleSaveClick = async () => {
// 로직 변경 당시 추가됐던 확인 모달 off 처리 함수
confirmModalOff();
try {
// 기존 formData를 업데이트하는 객체
let updatedFormData = { ...formData };
// 이미지가 있을 시 따로 URL을 가져오는 함수
if (formData.image instanceof File) {
const imageData = new FormData();
imageData.append('image', formData.image);
const res = await getImageUrl(imageData as ImageData);
if (res?.url) {
updatedFormData = {
...formData,
image: res.url,
};
setFormData(updatedFormData);
}
}
// 최종 데이터 전송
const profileUpdateResponse = await updateProfile(
userProfile?.code,
updatedFormData as ChangeProfilesFormData,
);
setUserProfile(profileUpdateResponse);
setIsEditing(false);
} catch (error: unknown) {
if (isAxiosError(error)) {
ToastSelect({ type: 'error', message: error?.response?.data.message });
} else {
ToastSelect({ type: 'error', message: '예상치 못한 에러가 발생했습니다.' });
}
} finally {
setRenewalTime(!renewalTime);
}
};
// 초기 상태값 세팅
const updateFormData = useCallback(() => {
if (userProfile) {
const {
nationality,
family,
bloodType,
nickname,
birthday,
sns,
job,
mbti,
city,
image,
content,
} = userProfile;
const newFormData: ChangeProfilesFormData = {
nationality,
family,
bloodType,
nickname,
birthday,
sns,
job,
mbti,
city,
image,
content,
};
setFormData(newFormData);
}
}, [userProfile]);
- 조언받은대로 로직을 변경해보았다.
- 위 로직은 받아온
userProfile
객체를 바탕으로 원하는 키만 뽑아내고 이를formData
상태값에 넣어주는 방식이며, 이를 이용해PATCH
전송 로직을 구성하였다. - 이렇게 변경함으로서
handleSaveClick
이 수행하는 작업의 수를 훨씬 줄일 수 있었고, 새로고침하지 않더라도 상태값이 변경된 상태로 유지되는 문제 또한 해결할 수 있었다.
🏷️ 추가적으로 고민해볼 사항
- 일단 이정도로 마무리를 지었지만, 여전히 코드를 좀 더 간소화 시킬 수 있지 않을까? 라는 아쉬움이 남는다.. 시간이 날 때마다 조금씩 고민해봐야겠다고 생각했다.
우째하긴~ 이렇게 하믄 된다! 👍
'Front-End Study > 이건 우째해야 할까..' 카테고리의 다른 글
무한 스크롤.. 이건 우째해야 할까.. (1) | 2024.06.11 |
---|