본문으로 건너뛰기

"hook 관리 컨벤션" 태그로 연결된 1개 게시물개의 게시물이 있습니다.

모든 태그 보기

· 약 5분
최지훈

들어가며

  • React-Query를 활용한 서버 상태 관리 글을 작성하면서 공부한 내용을 실제 야놀자 클론 코딩 프로젝트에 적용해 보았습니다.
  • 컴포넌트와 React-Query hook, axios 로직을 분리하여 관리했던 경험과 장단점을 함께 다룹니다.

실제 적용 내용

행동

  • React-Query hook 사용법을 이해하는 것을 넘어서 어떻게 하면 효율적으로 관리할 수 있을지 고민해 보았습니다.
  • React-Query에서 제공해주는 hook인 useQuery와 useMutation을 리액트 컴포넌트 안에서 바로 사용할 수 있지만, hook에 사용되는 코드가 비지니스 로직이라면 컴포넌트와 분리할 필요가 있다고 판단하였습니다.
  • 이에 React-Query hook에 작성되는 코드가 View 로직에 가까운지 비지니스 로직에 가까운지 생각해 보았습니다.
const Cart = () => {
const {
data: cartData,
isLoading,
} = useQuery({
queryKey: ["fetchCarts"],
queryFn: async (): Promise<CartData> => {
const { data }: { data: FetchCartResult } = await authInstance.get("carts");
return data.data;
},
});

return !isLoading && cartData ? (
<장바구니 View>
) : (
<로딩 View>
);
};

export default Cart;
  • 위 코드가 지금은 간단해 보이는 코드이지만, 만약 조금이라도 View 혹은 비지니스 로직이 추가되면 아주 복잡한 컴포넌트가 될 가능성이 높다고 생각하였습니다.
  • 따라서 View에 영향을 주는 부분과 그렇지 않는 코드 (비지니스 로직)을 아래와 같이 분리해 보았습니다.

View 로직

  • API 요청 이후 최종적으로 받아오는 cartData
  • API 요청 상태의 로딩 상태를 알려주는 isLoading
  • Cart 컴포넌트의 return 값

비지니스 로직

  • useQuery의 queryKey, queryFn 또한 이후에 사용될 수도 있는 options

  • axios를 활용한 비동기 요청 함수

  • 비지니스 로직에서도 useQuery에서 onError, onSuccess 등과 같은 options들이 추가적으로 사용될 수 있기 때문에 비동기 요청 함수 또한 따로 분리하는 것이 좋다고 판단하였습니다.

  • 위와 같이 로직을 분리하여 생각하고 아래와 같이 각 로직을 관리해 보았습니다.

// 컴포넌트

const Cart = () => {
const {
data: cartData,
isLoading,
} = useFetchCarts();

return !isLoading && cartData ? (
<장바구니 View>
) : (
<로딩 View>
);
};

export default Cart;
// React-Query hook

export const useFetchCarts = () =>
useQuery({
queryKey: ["fetchCarts"],
queryFn: () => fetchCarts(),
});
// axios API 호출

export const fetchCarts = async (): Promise<CartData> => {
const { data }: { data: FetchCartResult } = await authInstance.get("carts");

return data;
};

효과

  • 컴포넌트에서는 view 로직을, hook과 비동기 처리에서는 비지니스 로직을 따로 집중해서 관리할 수 있게 되었습니다.

  • 컴포넌트의 경우 공통 컴포넌트로 사용헤야하는 상황이 오면 쉽게 대응할 수 있게 되었습니다.

  • 또한 에러 처리를 할 때, 404 페이지로 이동하거나 toast를 보여준다거나 하는 View와 관련된 에러는 컴포넌트에서 관리하고, 이 외의 에러처리에 대해서는 useQuery의 onError를 활용하여 에러 관리를 할 수 있게 되었습니다.

    // 컴포넌트

    const Cart = () => {
    const {
    data: cartData,
    isLoading,
    isError
    } = useFetchCarts();

    if (isError) {return "View 에러 처리"}

    return !isLoading && cartData ? (
    <장바구니 View>
    ) : (
    <로딩 View>
    );
    };

    export default Cart;
    // React-Query hook

    export const useFetchCarts = () =>
    useQuery({
    queryKey: ["fetchCarts"],
    queryFn: () => fetchCarts(),
    onError: "View 이외 에러 처리 함수"
    });