이번 전온팀 프로젝트를 진행하며 만들어서 사용한 custom hook 두가지를 소개해보고자 한다.
전온팀 프로젝트에는 즐겨찾기를 할 수 있는 기능들이 왕 많았다. (안내,콘텐츠,부스 등..)
그래서 즐겨찾기 진행하는 로직을 한군데에서 관리하고 하나의 훅을 여러곳에서 사용하기 위해 useBookmark 라는 훅을 만들었다.
export default function useBookmark({
id,
queryKey,
bookmarkFn,
bookmarkCancelFn,
initialBookmarkState,
}: {
id: number;
queryKey: string;
bookmarkFn: (id: number) => Promise<any>;
bookmarkCancelFn: (id: number) => Promise<any>;
initialBookmarkState: boolean | null;
}) {
const queryClient = useQueryClient();
const [like, setLike] = useState(initialBookmarkState || false);
const mutation = useMutation({
mutationFn: async (userAction: 'UNLIKE' | 'LIKE') => {
if (userAction === 'LIKE') {
await bookmarkFn(id); // 북마크 추가
} else {
await bookmarkCancelFn(id); // 북마크 취소
}
},
onMutate: async (userAction) => {
await queryClient.cancelQueries({
queryKey: [queryKey, id],
});
const prevDetails = queryClient.getQueryData([queryKey, id]);
queryClient.setQueryData([queryKey, id], (prev: any) => {
if (!prev) return prev;
return {
...prev,
bookmark: userAction === 'LIKE',
};
});
return { prevDetails };
},
onError: (_error, _, context) => {
if (context?.prevDetails) {
queryClient.setQueryData([queryKey, id], context.prevDetails);
}
},
onSettled: () => {
queryClient.invalidateQueries({
queryKey: [queryKey, id],
});
},
});
useEffect(() => {
if (initialBookmarkState !== null) {
setLike(initialBookmarkState);
}
}, [initialBookmarkState]);
const toggleBookmark = () => {
const action = like ? 'UNLIKE' : 'LIKE';
mutation.mutate(action);
setLike((prev) => !prev);
};
return {
like,
toggleBookmark,
};
}
1. react-query 활용
2. 낙관적 업데이트
3. 유지 보수
전온팀의 부스 검색 시 사용되는 debounce 훅이다. 사용자의 입력값 변화에 딜레이를 주어 불필요한 연산이나 API 호출을 줄이는 데 사용한다.
export default function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}