[React/TS] Selector 효율적으로 작성하기

예구·2023년 3월 25일
0

특화PJT

목록 보기
3/8
post-thumbnail
post-custom-banner

React와 Typescript, Recoil을 사용하여 여행지를 추천하는 프로젝트를 진행하고 있다.
목록 Page를 구현하는 도증, 데이터를 잘 받아오는지 확인하기위해 코드를 비효율적으로 작성하였고, 이를 수정하여 효율적인 코드로 작성해보고자 한다.



1. 코드 설명

// TripListSelector.ts

import { atom, selector } from "recoil";
import axios from "axios";
import { customAxios } from "./customAxios";
import { ListType } from "../types/tripListTypes";

// 여행지 목록 불러오는 함수
const getTripListData = (
  contentTypeId: number,
  area: number,
  barrier: string,
  page: number,
  size: number
): Promise<ListType[]> =>
  customAxios
    .get(
      `location/list/${contentTypeId}?area=${area}&barrier=${barrier}&page=${page}&size=${size}`
    )
    .then((response) => {
      // console.log(response.data);
      return response.data.contents;
    })
    .catch((error) => {
      console.log(error);
    });



// 식당 목록
export const RestaurantListSelector = selector<ListType[]>({
  key: "RestaurantListSelector",
  get: async () => {
    try {
      const restaurantList = await getTripListData(39, 1, "10000", 0, 10);

      return restaurantList;
    } catch (err) {
      throw err;
    }
  },
});

// 숙박 목록
export const AccommodationListSelector = selector<ListType[]>({
  key: "AccommodationListSelector",
  get: async () => {
    try {
      const accommodationList = await getTripListData(32, 1, "10000", 0, 10);

      return accommodationList;
    } catch (err) {
      throw err;
    }
  },
});

// 관광지 목록
export const TourSpotListSelector = selector<ListType[]>({
  key: "TourSpotListSelector",
  get: async () => {
    try {
      const tourSpotList = await getTripListData(12, 1, "10000", 0, 10);

      return tourSpotList;
    } catch (err) {
      throw err;
    }
  },
});

// 문화시설 목록
export const CultureListSelector = selector<ListType[]>({
  key: "CultureListSelector",
  get: async () => {
    try {
      const cultureList = await getTripListData(14, 1, "10000", 0, 10);

      return cultureList;
    } catch (err) {
      throw err;
    }
  },
});

// 레포츠 목록
export const LeportsListSelector = selector<ListType[]>({
  key: "LeportsListSelector",
  get: async () => {
    try {
      const leportsList = await getTripListData(28, 1, "00000", 0, 10);

      return leportsList;
    } catch (err) {
      throw err;
    }
  },
});

// 쇼핑 목록
export const ShoppingListSelector = selector<ListType[]>({
  key: "ShoppingListSelector",
  get: async () => {
    try {
      const shoppingList = await getTripListData(38, 1, "00000", 0, 10);

      return shoppingList;
    } catch (err) {
      throw err;
    }
  },
});



위의 코드는 Recoil이라는 상태 관리 라이브러리를 사용하여 여행지 정보를 가져오는 selector를 정의하고 있다.

getTripListData 함수는 axios를 사용하여 서버로부터 데이터를 가져오는 함수다. 이 함수는 contentTypeId, area, barrier, page, size를 인자로 받아서, 서버 API에 요청을 보내고, 응답으로 받은 데이터에서 contents를 추출하여 Promise<ListType[]> 형태로 반환한다.

이후 각 selectorget 함수 내에서 getTripListData 함수를 호출하여 데이터를 가져오고, 가져온 데이터를 반환한다. 각 selectorkey라는 고유 식별자를 가지고 있으며, 이 key는 캐싱 등의 목적으로 사용된다.

예를 들어, RestaurantListSelector39contentTypeId에 해당하는 식당 목록을 가져오는 selector이며, 이 selector를 사용하는 컴포넌트에서 해당 데이터를 참조하면, get 함수가 호출되어 데이터를 가져오게 된다. 이후 같은 selector를 참조하는 다른 컴포넌트에서는 이전에 가져온 데이터를 캐싱하여 다시 get 함수를 호출하지 않고 사용할 수 있다.



2. 문제점과 수정 코드

해당 코드의 문제점은 selector가 거의 동일한 getTripListData 함수를 사용한다는 것이다. 이를 개선하기 위해서 getTripListData 함수를 재사용할 수 있도록 수정해 나갈 것이다.

하나의 selector에서 여러 종류의 목록을 가져올 수 있도록 contentTypeIdbarrier 값을 인자로 받는 새로운 함수를 만들어서 이를 재사용할 것이다. 이는 코드의 중복을 줄이고, 코드의 유지보수성과 가독성을 향상시키기 위함이다.



// TripListSelector.ts

import { atom, selector } from "recoil";
import axios from "axios";
import { customAxios } from "./customAxios";
import { ListType } from "../types/tripListTypes";

const getTripListData = async (
  contentTypeId: number,
  area: number,
  barrier: string,
  page: number,
  size: number
): Promise<ListType[]> => {
  try {
    const response = await customAxios.get(
      `location/list/${contentTypeId}?area=${area}&barrier=${barrier}&page=${page}&size=${size}`
    );
    return response.data.contents;
  } catch (error) {
    console.log(error);
    throw error;
  }
};

const getListSelector = (
  key: string,
  contentTypeId: number,
  barrier: string
) => {
  return selector<ListType[]>({
    key: key,
    get: async () => {
      try {
        const list = await getTripListData(contentTypeId, 1, barrier, 0, 10);
        return list;
      } catch (err) {
        throw err;
      }
    },
  });
};

// 식당 목록
export const RestaurantListSelector = getListSelector(
  "RestaurantListSelector",
  39,
  "10000"
);

// 숙박 목록
export const AccommodationListSelector = getListSelector(
  "AccommodationListSelector",
  32,
  "10000"
);

// 관광지 목록
export const TourSpotListSelector = getListSelector(
  "TourSpotListSelector",
  12,
  "10000"
);

// 문화시설 목록
export const CultureListSelector = getListSelector(
  "CultureListSelector",
  14,
  "10000"
);

// 레포츠 목록
export const LeportsListSelector = getListSelector(
  "LeportsListSelector",
  28,
  "00000"
);

// 쇼핑 목록
export const ShoppingListSelector = getListSelector(
  "ShoppingListSelector",
  38,
  "00000"
);

getListSelector 함수를 추가로 정의하였고, key, contentTypeId, barrier 값을 인자로 받아서 selector를 반환한다. 이 함수는 getTripListData 함수를 호출하여 데이터를 가져오는데 사용되며, contentTypeIdbarrier 값은 getListSelector 함수를 호출할 때 인자로 전달된다.


일단은 여기까지 수정을 하고, 다른 기능을 더 추가하면 위의 코드도 더 수정하여 올릴 것이다.

profile
우당탕탕 FE 성장기
post-custom-banner

0개의 댓글