[나와 닮은 못난이 농산물 똑닮안] 4. 리팩토링1 (react-query, 로딩 컴포넌트)
개요
해커톤이 끝난 지 한 달이 조금 넘게 지났고, 그동안 꽤 많은 리팩토링이 진행되었다. 우선 지저분했던 코드들을 정리하며 폴더 구조 변경 및 로직을 개선했고, UX 향상을 위한 몇 가지 수정을 거쳤다. 이번 글에서는 리팩토링을 하며 직접적으로 와닿았던 4가지의 변화를 정리하고, 서비스의 기획/디자인 측면에서 대대적으로 변경된 결과 페이지를 소개하고자 한다.
1. React Query 도입
해커톤 당시 실패했던 react-query
도입. 너무 아쉬웠고 가장 빠르게 적용하고 싶었던 리팩토링 포인트였다.
근데 왜 도입하려고 했나?
1. react-query
의 존재를 알게되었으니까! 프로젝트에 적용해보고 싶으니까! ( ?😮? )
2. API 호출 시 로딩, 에러를 깔끔하게 처리할 수 있으니까!
3. 캐싱을 통해 성능을 개선시킬 수 있으니까! (POST 요청에서는 의미가 없었다..ㅎ)
API 함수 변경
위와 같은 이유를 들며 일단 기존 API 함수를 변경했다. react-query
에서 에러 처리를 할 것이기 때문에 기존의 try-catch
가 필요 없어졌기 때문이다.
Before
export const getResult = async (data: SelectedProps) => {
try {
const res = await axios.post(`${baseURL}/crop/products`, data);
return res.data;
} catch (e) {
console.log(e);
}
};
After
export const getResult = async (data: SelectedProps) => {
const res = await axios.post(`${baseURL}/crop/products`, data);
return res.data;
};
API 호출 부분 변경
API를 호출하는 부분에 useMutation
을 적용하면서 아래와 같이 변경되었다.
변경사항 | Before | After |
isLoading, isError 관리 | useState로 관리 | useMutation 반환 값으로 관리 |
호출 위치 | 결과 페이지로 이동할 때 호출 | 선택 페이지의 [결과 확인] 버튼 클릭 시 호출 |
Before (pages/result.tsx)
const [isLoading, setIsLoading] = useState(true);
const [isError, setIsError] = useState('');
useEffect(() => {
getResult(selected).then((res) => {
if (res.result) {
setResult(res.result);
setResultType(res.result.type);
setIsLoading(false);
} else {
setIsError(res.message);
alert(res.message);
}
});
After (pages/select.tsx)
const {
data: resultData,
mutate: resultMutation,
isLoading: resultLoading,
isSuccess: resultSuccess,
isError: resultError,
} = useMutation(getResult);
const handleCaptureClick = () => {
resultMutation(selectedState);
};
useEffect(() => {
if (resultSuccess) {
if (resultData.result) navigate('/result', { state: resultData.result });
else {
alert(resultData.message);
}
}
}, [resultSuccess]);
return (
...
<ImageFileUpload onClickButton={handleCaptureClick} />
...
)
호출 위치 자체가 바뀌다 보니 결과 페이지로 이동 시 state로 API응답을 넘겨주어야 했지만, 그래서 뭔가 이게 맞는 건가? 싶은데 확실히 코드는 깔끔해졌다고 생각한다. 게다가 기존에는 결과 페이지에서 새로고침을 했을 때 다시 로딩이 뜨는 현상이 있었는데, 이 부분을 해결해서 너무 만족스러웠다.
비하인드
사실 처음부터 위의 구조를 가져간 것이 아니였다. react-query를 잘 알지 못했고 (지금도 잘 모름..) useQuery 하나만 알고 있는 상태에서 냅다 적용한 것이기에, POST 요청에서는 useMutation을 쓰는 것이라는 것을 한참 찾아보다가 알게 되었다. 첫 시도에는 아래처럼 result 페이지의 useEffect에서 mutation을 호출했는데, 구글링 해봤을 때 이렇게 쓰는 사람은 없는 것 같아 지금 구조로 변경했다.
const {
mutate: resultMutation,
isLoading: resultLoading,
} = useMutation(getResult, {
onSuccess: (data) => {
if (data.result) {
setResult(data.result);
setResultType(data.result.type);
} else {
alert(data.message);
}
},
onError: (error) => {
navigate('/');
},
});
useEffect(() => {
resultMutation(selected);
}, []);
2. 로딩 컴포넌트 개선
로딩 컴포넌트의 경우, 이미지들의 setInterval
로 구현되어 있었다. 해커톤 당시 로딩 컴포넌트 구현 방법을 찾아봤을 때 이 방법이 나왔던 것 같다. 하지만, 이렇게 이미지를 활용할 경우 네트워크 탭에서 로딩이 이루어지는 동안 이미지들이 계속 반복적으로 다운로드 하는 현상을 발견했고(근데 사실 캐싱해서 성능에 영향은 없는 것 같기도..), 좀 더 찾아보니 GIF
로 구현하는 것이 보다 일반적인 것 같았다.
그래서 Image to GIF로 수정을 진행했고, 조금 더 나은 UX를 이루었다(라고 믿는다).
'Project > 나와 닮은 못난이 농산물 똑닮안' 카테고리의 다른 글
[나와 닮은 못난이 농산물 똑닮안] 5. 리팩토링2 (모달 컴포넌트, Layout Shift) (5) | 2023.05.17 |
---|---|
[나와 닮은 못난이 농산물 똑닮안] 3. 36시간 내에 MVP 완성하기2 (1) | 2023.04.16 |
[나와 닮은 못난이 농산물 똑닮안] 2. 36시간 내에 MVP 완성하기1 (1) | 2023.04.15 |
[나와 닮은 못난이 농산물 똑닮안] 1. 프로젝트 개요 (feat. 구름톤) (3) | 2023.04.12 |