Redux -> SWR로 교체하기
기존 코드
기존 reduxthunks
로 데이터를 가지고 오는 경우 다음과 같이, useEffect
로 params값이 변할 때마다 데이터를 갱신하도록 처리했습니다.
const handleFetchParticipantList = () => {
if (procedureId) {
dispatch(fetchParticipants(companyId, procedureId));
}
};
useEffect(() => {
handleFetchParticipantList();
}, [sort, order, status, page, isBookmarked, keyword]);
redux thunks: fetchParticipants
를 dispatch하면, 데이터 fetch 후 response를 각각 store에 저장합니다.
export const fetchParticipants =
(companyId: string, procedureId: string) =>
async (dispatch: any, getState: any) => {
const { participants: participantsState } = getState();
const { params } = participantsState;
dispatch(stateReset());
try {
const response = await getParticipantsByProcedureId(
companyId,
procedureId,
queryString(params),
);
const { examinations, totalCount, maxPage } = response;
dispatch(examinationsFetched({ examinations, totalCount, maxPage }));
} catch (error: any) {
dispatch(
errorOccurred({
status: error.response.status,
code: error.response.data.code,
info: error.response.data.info,
}),
);
}
};
그러면, 갱신된 redux store 값에 맞춰 해당 페이지가 리렌더링됩니다. 아래 코드에서 useSelector로 가져온 examinations
값이 fetchParticipants
로 갱신된 데이터입니다.
const { examinations } = useSelector((state: RootState) => state.participants);
문제
여기엔 세가지 문제가 있었습니다.
1. 가독성이 좋지 않음
fetch 시점을 조작하기 위한 비즈니스 로직과 화면을 표현하는 로직과 섞여 가독성이 나빴습니다.
2. 안정성이 떨어짐
SSE로 알람을 받을 때 redux값이 갱신되도록 처리한 부분이 있었는데, SSE가 유실되는 경우 새로운 데이터를 갱신할 수 없었습니다. 그리고, 해당 경우 프론트단이 유실여부를 알 수 있는 방법이 없어 에러핸들링도 할 수 없었습니다.
3. API 관련 데이터 관리가 불편
API 요청시 로딩 여부, 에러, 성공 여부 등 관련 데이터를 따로 리덕스로 관리해줘야 했습니다.
해결 ( swr hook 만들기 )
swr 훅을 만들어서 fetch와 관련된 비즈니스 로직을 모듈화 했습니다.
export const useGetExaminations = ({
companyId,
procedureId,
options,
}: {
companyId: string;
procedureId?: string;
options?: any;
}) => {
const API_KEY = `/api/v1/participants?companyId=${companyId}&procedureId=${procedureId}`;
const { params } = useSelector((state: RootState) => state.participants);
const { t } = useLocalization();
const getExamination = async (url: string) => {
try {
const { data } = await axiosInstance.get(url);
return data;
} catch (error: any) {
if (error?.response.message) {
Toast.show(t(error.response.message), ToastType.Fail);
return;
}
}
};
const { data, mutate, error, isLoading } = useSWR(
API_KEY + queryString(params),
procedureId ? getExamination : null,
options && { ...options },
);
return { data, mutate, error, isLoading };
};
//페이지에서 해당 데이터 사용시
const { data: examinations, isLoading } = useGetExaminations();
따라서 위 문제들을 다음과 같이 해결할 수 있었습니다.
1. 가독성이 좋지 않음
-> swr훅으로 비즈니스 로직 분리했기에, 화면 로직엔 swr으로 반환한 데이터만 표시
2. 안정성이 떨어짐
-> SSE가 유실되더라도, swr은 사용자의 focus를 감지해 revalidate할 수 있습니다.
3. API 관련 데이터 관리가 불편
-> swr의 useSWR은 해당 데이터를 반환해주기에, 따로 프론트단에서 값을 관리할 필요가 없습니다.
댓글남기기