React와 Typescript, Recoil을 사용하여 여행지를 추천하는 프로젝트를 진행하고 있다.
목록 Page를 구현하는 도증, 데이터를 잘 받아오는지 확인하기위해 코드를 비효율적으로 작성하였고, 이를 수정하여 효율적인 코드로 작성해보고자 한다.
// 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[]>
형태로 반환한다.
이후 각 selector
는 get
함수 내에서 getTripListData
함수를 호출하여 데이터를 가져오고, 가져온 데이터를 반환한다. 각 selector
는 key
라는 고유 식별자를 가지고 있으며, 이 key
는 캐싱 등의 목적으로 사용된다.
예를 들어, RestaurantListSelector
은 39번 contentTypeId
에 해당하는 식당 목록을 가져오는 selector
이며, 이 selector
를 사용하는 컴포넌트에서 해당 데이터를 참조하면, get
함수가 호출되어 데이터를 가져오게 된다. 이후 같은 selector
를 참조하는 다른 컴포넌트에서는 이전에 가져온 데이터를 캐싱하여 다시 get
함수를 호출하지 않고 사용할 수 있다.
해당 코드의 문제점은 selector
가 거의 동일한 getTripListData
함수를 사용한다는 것이다. 이를 개선하기 위해서 getTripListData
함수를 재사용할 수 있도록 수정해 나갈 것이다.
하나의 selector
에서 여러 종류의 목록을 가져올 수 있도록 contentTypeId
와 barrier
값을 인자로 받는 새로운 함수를 만들어서 이를 재사용할 것이다. 이는 코드의 중복을 줄이고, 코드의 유지보수성과 가독성을 향상시키기 위함이다.
// 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
함수를 호출하여 데이터를 가져오는데 사용되며, contentTypeId
와 barrier
값은 getListSelector
함수를 호출할 때 인자로 전달된다.
일단은 여기까지 수정을 하고, 다른 기능을 더 추가하면 위의 코드도 더 수정하여 올릴 것이다.