
TanStack Query(FKA React Query)는 종종 웹 애플리케이션용 누락된 데이터 가져오기 라이브러리로 설명되지만 좀 더 기술적인 용어로 말하면 웹 애플리케이션에서 서버 상태 가져오기, 캐싱, 동기화 및 업데이트를 매우 쉽게 만듭니다.
대부분의 기존 상태 관리 라이브러리는 클라이언트 상태 작업에는 적합하지만 비동기 또는 서버 상태 작업에는 그다지 적합하지 않습니다 . 이는 서버 상태가 전혀 다르기 때문입니다 . 우선 서버 상태는 다음과 같습니다.
애플리케이션에서 서버 상태의 특성을 파악하면 진행하면서 더 많은 문제가 발생하게 됩니다
서버에서 데이터를 가져와 웹 프레임워크 내에서 비동기 처리를 하는 복잡한 과정을 좀 더 쉽게 처리하기 위함이다. 또한 장점을 정리하면,
onSuccess, onError의 중단 때문이다..!useQuery 메소드에서 버그 발생 및 앱 리팩토링/확장 시 에러가 쉽게 발생할 수 있는 상태 동기화가 제공되기 때문에 해당 메소드를 중단했다고 한다.오늘의 교훈 : 버전 체크를 잘하자, 예전에 쓴 코드 다시 쓸 때는 공식문서 잘 읽자.
// 헤더 및 공통 api 양식 작성해주기
export const Header = async () => ({
headers: {
Authorization: `Bearer ${await getStorage('Accesstoken')}`,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true',
},
});
export const api = {
get: <T = unknown>(path: string, init?: RequestInit) =>
request(path, init).then<T>(response => response.json()),
put: <T = unknown>(path: string, payload?: T, init?: RequestInit) =>
request(path, {
headers: init?.headers,
method: 'PUT',
body: JSON.stringify(payload),
}),
post: <T = unknown>(path: string, payload?: T, init?: RequestInit) =>
request(path, {
headers: init?.headers,
method: 'POST',
body: JSON.stringify(payload),
}),
delete: <T = unknown>(path: string, payload?: T, init?: RequestInit) =>
request(path, {
headers: init?.headers,
method: 'DELETE',
body: JSON.stringify(payload),
}),
};
// 위에서 작성한 양식 토대로 api 작성하기
export const fetchMyAnimalListInfo = async () => {
// 1. 타입 2. api 3. 헤더를 작성
return await api.get<Animal[]>('/animal/id001', await Header());
};
@tanstack/react-query를 설치해주자.yarn add @tanstack/react-query
import React from 'react';
import {View, FlatList, Text} from 'react-native';
import AnimalCard from './AnimalCard';
import styles from './style';
import {fetchMyAnimalListInfo} from '@/apis/animal';
import {useQuery} from '@tanstack/react-query';
// 위 데이터에 맞게 타입을 수정해주기.
type Animal = {
animalId: number;
animalName: string;
fileUrl: string;
selected: boolean;
};
const targetNumColumns = 3; // 원하는 열의 수
export default function AnimalCardlist() {
const {
data, // API 응답 결과를 반환하는 값임. state에 저장해도 되지만 여기서는 그냥 불러와서 그대로 씀
isLoading, // 데이터 로딩 중일 때 true값을 반환함. 따라서 view에 isLoading? 해서 로딩 페이지 보여줄 수 있음
isError, // 1. isError: 쿼리가 오류났다? 예를 들어서 500 에러가 났다? 그러면 이게 true값이 되어서 돌발! 돌발! 하고 알려준다는 뜻임.
// 근데 나는 이 페이지에서 쿼리를 세 네개 썼고, 이 값이 중복 되면 안되니까 isError라는 값을 isBookListError라는 이름으로 바꿔주세요~ 하고 써두었음.
error // 2. error: 1번에서 오류났는데 그러면 메세지가 있어야 뭔 에런지 알겠죠? 그럼 여기서 isError가 true면 error를 써서 메세지를 받음.
// 나는 이 페이지에서 쿼리를 세 네개 썼고, 이 값이 중복 되면 안되니까 error를 bookListError로 바꿔서 메세지를 받음.
// useQuery<Animal[]>로 호출 성공! 이러면 받아오는 타입을 지정해줌.
} = useQuery<Animal[]>({
queryKey: ['animalList'], // 쿼리의 고유 키. 리스트로 넣어주면 오류가 해결됨. 이는 공문에도 리스트로 넣으라고 쓰여있긴 함
queryFn: fetchMyAnimalListInfo, // 실제 데이터를 가져오는 함수
});
// 로딩 중이면 로딩 메시지를 출력
if (isLoading) return console.log('로딩');
// 에러가 발생하면 에러 메시지와 함께 에러의 내용을 출력하는데 hotToast등으로 에러났다고 말하거나 처리하기
if (isError) return console.log('에러', error);
// 응답받은 데이터를 Animal 타입 배열로 변환해서 넣어주는데....
// 이건 이렇게 안하고 state에 저장해도 됨.
// 그러나 나중에 동물 선택하고 리스트 업데이트 해야 하고 그러면 업데이트 로직 생각해볼 것
const animalsArray: Animal[] = data as Animal[];
const totalCards = animalsArray.length;
const numColumns = Math.min(
targetNumColumns,
Math.ceil(totalCards / targetNumColumns),
);
const missingCards = numColumns - (totalCards % numColumns);
// 타겟 열 수와 다르다면 hidden card 만드는 예외처리
if (missingCards !== targetNumColumns) {
for (let i = 0; i < missingCards; i++) {
animalsArray.push({
animalId: i,
animalName: '',
fileUrl: '',
selected: false,
});
}
}
return (
<View>
<FlatList
key={numColumns}
horizontal={false} // 수직으로 정렬
numColumns={numColumns} // 한 줄에 표시할 카드 수 설정
data={animalsArray} <----------------------------여기에 fetch 해 온 아이템 다 들어가는 것
keyExtractor={item => item.animalId.toString()}
renderItem={({item}) => {
if (!item.animalName) {
return <View style={styles.hiddenCard} />;
}
return (
<AnimalCard
id={item.animalId.toString()}
title={item.animalName}
imgurl={item.fileUrl}
/>
);
}}
/>
</View>
);
}

useMutation을 사용해 post, put, delete 요청 하는 방법을 작성해보겠다!