데이터 통신
통신
대표적인 api 통신 tanstack-query, axios, fetch 정리하겠습니다.
1. React Query의 기본 개념
- React Query란?
React Query는 React 애플리케이션에서 비동기 데이터를 효율적으로 관리할 수 있도록 도와주는 라이브러리입니다. API 데이터를 캐싱하고, 자동으로 리패칭하며, 네트워크 상태에 따라 데이터를 동기화하는 기능을 제공합니다.
주요 기능
자동 캐싱: API 데이터를 자동으로 저장하여 불필요한 요청을 방지
백그라운드 리패칭: 오래된 데이터를 자동으로 새로고침
데이터 동기화: API 데이터와 UI 상태를 자동으로 동기화
쿼리 키 기반 데이터 관리: 동일한 데이터를 필요로 하는 여러 컴포넌트에서 상태를 공유 가능
에러 핸들링 내장: 네트워크 에러 발생 시 자동으로 재시도
2. useQuery() useMutation() 사용법
2.1 useQuery(): 데이터 가져오기 (Fetching)
useQuery 는 서버에서 데이터를 가져오는 데 사용됩니다.
예제: 사용자 목록 불러오기
import { useQuery } from '@tanstack/react-query'
const fetchUsers = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users')
if (!response.ok) throw new Error('Network response was not ok')
return response.json()
}
const Users = () => {
const { data, isLoading, error } = useQuery(['users'], fetchUsers)
if (isLoading) return <p>Loading...</p>
if (error) return <p>Error: {error.message}</p>
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}
2.2 useMutation(): 데이터 변경 (POST, PUT, DELETE)
useMutation()은 서버 데이터를 변경할 때 사용됩니다.
예제: 사용자 추가
import { useMutation, useQueryClient } from '@tanstack/react-query'
const addUser = async (newUser) => {
const response = await fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newUser),
})
return response.json()
}
const AddUser = () => {
const queryClient = useQueryClient()
const mutation = useMutation(addUser, {
onSuccess: () => {
queryClient.invalidateQueries(['users'])
},
})
return (
<button onClick={() => mutation.mutate({ name: 'New User' })}>
Add User
</button>
)
}
3. 쿼리 키 & 캐싱 전략
3.1 쿼리 키 (queryKey
)
- useQuery() 에서 쿼리 키를 사용하여 캐싱을 제어할 수 있습니다.
- 동일한 쿼리 키를 가진 요청은 캐싱된 데이터를 반환합니다.
const { data } = useQuery(['users'], fetchUsers)
3.2 캐싱 전략 설정
- staleTime: 데이터가 만료되기 전까지 재요청하지 않음
- cacheTime: 캐싱된 데이터가 메모리에 유지되는 시간
const { data } = useQuery(['users'], fetchUsers, {
staleTime: 1000 * 60 * 5, // 5분 동안 데이터가 신선하다고 간주
cacheTime: 1000 * 60 * 10, // 10분 후 캐시 삭제
})
4. useMutation() 활용한 데이터 변경
4.1 데이터 추가, 수정, 삭제 처리
- onMutate: 뮤테이션이 실행되기 전에 캐시 업데이트
- onSuccess: 성공 시
queryClient.invalidateQueries()
를 사용하여 데이터 갱신
const mutation = useMutation(addUser, {
onMutate: async (newUser) => {
await queryClient.cancelQueries(['users'])
const previousUsers = queryClient.getQueryData(['users'])
queryClient.setQueryData(['users'], (old) => [...old, newUser])
return { previousUsers }
},
onError: (err, newUser, context) => {
queryClient.setQueryData(['users'], context.previousUsers)
},
onSettled: () => {
queryClient.invalidateQueries(['users'])
},
})
5. 낙관적 업데이트 & 배치 처리
5.1 낙관적 업데이트 (Optimistic Updates)
const mutation = useMutation(updateUser, {
onMutate: (newUser) => {
queryClient.setQueryData(['users', newUser.id], newUser)
},
onSuccess: () => {
queryClient.invalidateQueries(['users'])
},
})
6. useInfiniteQuery 를 활용한 무한 스크롤
6.1 무한 스크롤 구현
const { data, fetchNextPage } = useInfiniteQuery(['users'], fetchUsers, {
getNextPageParam: (lastPage, allPages) => lastPage.nextCursor,
})
7. Axios 개요
7.1 Axios란?
Axios는 브라우저와 Node.js 환경에서 사용할 수 있는 HTTP 클라이언트 라이브러리로, Promise 기반으로 동작하며, RESTful API와 쉽게 상호작용할 수 있도록 도와줍니다.
7.2 Fetch API와의 차이
기능 | Axios | Fetch API |
---|---|---|
기본 제공 기능 | 자동 JSON 변환, 요청 인터셉터 등 | 수동 JSON 변환 필요 |
에러 핸들링 | 상태 코드 기반 자동 오류 처리 | catch 로만 처리 가능 |
요청 취소 | CancelToken 제공 | AbortController 필요 |
예제:
// Axios 사용 예제
axios
.get('https://jsonplaceholder.typicode.com/posts')
.then((response) => console.log(response.data))
.catch((error) => console.error(error))
// Fetch 사용 예제
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error(error))
8. Axios 설치 및 기본 사용법
8.1 Axios 설치
npm install axios
8.2 기본적인 GET 요청
axios
.get('https://jsonplaceholder.typicode.com/users')
.then((response) => console.log(response.data))
.catch((error) => console.error(error))
8.3 기본적인 POST 요청
axios
.post('https://jsonplaceholder.typicode.com/posts', {
title: 'Axios Study',
body: 'Learning Axios',
userId: 1,
})
.then((response) => console.log(response.data))
.catch((error) => console.error(error))
9. Axios 요청 옵션
9.1 Headers 설정
axios
.get('https://api.example.com/data', {
headers: {
Authorization: 'Bearer token123',
'Content-Type': 'application/json',
},
})
.then((response) => console.log(response.data))
9.2 Query Parameters (쿼리 스트링) 사용
axios
.get('https://api.example.com/users', {
params: {
id: 123,
role: 'admin',
},
})
.then((response) => console.log(response.data))
9.3 Timeout 설정
axios
.get('https://api.example.com/slow-response', { timeout: 5000 })
.then((response) => console.log(response.data))
.catch((error) => console.error('Request timeout!', error))
10. 응답 처리 및 에러 핸들링
10.1 응답 데이터 처리
axios
.get('https://jsonplaceholder.typicode.com/users')
.then((response) => console.log(response.data)) // response.data에 실제 데이터가 포함됨
.catch((error) => console.error(error))
10.2 에러 핸들링
axios
.get('https://api.example.com/404')
.then((response) => console.log(response.data))
.catch((error) => {
if (error.response) {
console.log('Error:', error.response.status, error.response.data)
} else if (error.request) {
console.log('No response received:', error.request)
} else {
console.log('Error setting up request:', error.message)
}
})
11. Axios Interceptors (인터셉터)
11.1 요청 인터셉터
axios.interceptors.request.use(
(config) => {
config.headers.Authorization = `Bearer token123`
return config
},
(error) => Promise.reject(error),
)
11.2 응답 인터셉터
axios.interceptors.response.use(
(response) => {
console.log('Response received:', response)
return response
},
(error) => {
console.log('Error occurred:', error)
return Promise.reject(error)
},
)
12. Axios 인스턴스 활용
12.1 Axios 인스턴스 생성
const apiClient = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: { Authorization: 'Bearer token123' },
})
12.2 인스턴스를 이용한 요청
apiClient
.get('/users')
.then((response) => console.log(response.data))
.catch((error) => console.error(error))
13. 동시 요청 처리
13.1 axios.all()
과 axios.spread()
사용
axios
.all([
axios.get('https://api.example.com/users'),
axios.get('https://api.example.com/posts'),
])
.then(
axios.spread((users, posts) => {
console.log('Users:', users.data)
console.log('Posts:', posts.data)
}),
)
14. 파일 업로드 및 다운로드
14.1 파일 업로드
const formData = new FormData()
formData.append('file', fileInput.files[0])
axios
.post('https://api.example.com/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
})
.then((response) => console.log(response.data))
.catch((error) => console.error(error))
14.2 파일 다운로드
axios({
url: 'https://api.example.com/file.pdf',
method: 'GET',
responseType: 'blob',
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]))
const link = document.createElement('a')
link.href = url
link.setAttribute('download', 'file.pdf')
document.body.appendChild(link)
link.click()
})
15. CORS 이슈 해결
15.1 CORS란?
Cross-Origin Resource Sharing (CORS)은 보안상의 이유로 도메인 간 요청을 제한하는 정책입니다.
15.2 CORS 문제 해결 방법
- 서버에서
Access-Control-Allow-Origin: *
헤더 설정 - 프록시 서버 사용 (
proxy
옵션 설정)