TIL
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Today I Learned를 기록하는 공간입니다. 🔥🔥🔥
잔디를 클릭하면 내용확인이 가능합니다.
잔디를 클릭하면 내용확인이 가능합니다.
리액트 쿼리 팩토리 디자인 관리
MVP 1 ⇒ 구현된 API 전부 연결
MVP 2 ⇒ 사용자 경험을 위한 UI 반영 ( 무한 스크롤, 애니메이션 )
MVP 3 ⇒ 최적화
export const queryKeys = {
library: {
all: ['library'] as const,
lists: () => [...queryKeys.library.all, 'list'] as const,
list: (params: { lat: number; lng: number; libraryName?: string; page?: number; size?: number }) =>
[...queryKeys.library.lists(), params] as const,
details: () => [...queryKeys.library.all, 'detail'] as const,
detail: (id: string) => [...queryKeys.library.details(), id] as const,
},
libraryBook: {
all: ['library-book'] as const,
lists: () => [...queryKeys.libraryBook.all, 'list'] as const,
list: (params: {
latitude: number;
longitude: number;
page: number;
size: number;
bookName?: string;
sortType?: string;
}) => [...queryKeys.libraryBook.lists(), params] as const,
},
} as const;
export const mutationKeys = {
library: {
create: ['library', 'create'] as const,
update: ['library', 'update'] as const,
delete: ['library', 'delete'] as const,
},
} as const;
- 다음처럼 관리하면 쿼리키 관리에 용이
1. list(params) 사용 - 자동 Refetch
const { data } = useQuery(
libraryQueries.GET_LIBRARY({ lat: 37.5, lng: 127.0 })
);
// queryKey: ['library', 'list', { lat: 37.5, lng: 127.0 }]
params 값이 변경되면 React Query가 다른 쿼리로 인식해서 자동으로 새 데이터를 fetch합니다.
// lat이 37.5 → 37.6으로 변경
// queryKey: ['library', 'list', { lat: 37.6, lng: 127.0 }]
// 👉 자동으로 새로운 API 호출!
이건 "초기화"가 아니라 쿼리키가 달라져서 새로운 쿼리를 실행하는 겁니다.
2. lists() 사용 - 수동 Invalidation
queryClient.invalidateQueries({
queryKey: queryKeys.library.lists()
});
// ['library', 'list']로 시작하는 모든 쿼리 무효화
이건 prefix matching으로 동작합니다:
['library', 'list', { lat: 37.5, lng: 127.0 }] ✅ 무효화됨
['library', 'list', { lat: 37.6, lng: 127.1 }] ✅ 무효화됨
['library', 'list', { lat: 38.0, lng: 128.0 }] ✅ 무효화됨
['library', 'detail', '123'] ❌ 무효화 안됨
언제 lists() vs list(params) vs all을 쓸까?
✅ lists() - 모든 리스트에 영향
// 도서관 생성 후
libraryMutations.POST_LIBRARY({
onSuccess: () => {
// 어떤 위치에서 보든, 모든 리스트를 갱신해야 함
queryClient.invalidateQueries({ queryKey: queryKeys.library.lists() });
}
});
✅ list(params) - 특정 조건의 리스트만 영향
// 특정 위치의 도서관만 북마크 추가 (다른 위치는 영향 없음)
bookmarkMutation({
onSuccess: () => {
// 현재 보고 있는 리스트만 갱신
queryClient.invalidateQueries({
queryKey: queryKeys.library.list({ lat: 37.5, lng: 127.0 })
});
}
});
✅ all - 리스트+상세 모두 영향
// 도서관 삭제 시
deleteMutation({
onSuccess: () => {
// 리스트에서도 사라져야 하고, 상세페이지도 갱신되어야 함
queryClient.invalidateQueries({ queryKey: queryKeys.library.all });
}
});
요약
| 상황 | 사용할 키 | 이유 |
|---------------|----------------------|-----------------------|
| 도서관 생성/수정 | lists() | 모든 위치의 리스트가 영향받을 수 있음 |
| 도서관 삭제 | all | 리스트 + 상세 모두 영향 |
| 특정 위치 데이터만 갱신 | list(params) | 해당 조건만 갱신 |
| 도서관 상세 수정 | detail(id) + lists() | 해당 상세와 리스트 모두 갱신 |
핵심: lists()는 "모든 파라미터 조합의 리스트들"을 무효화할 때 사용합니다!
accessToken, refreshToken 구조에 대한 이해
Access Token과 RefreshToken은 똑같은 JWT, 단지 ACctessToken은 접근, RefreshToken은 재발급에 관여하는 것 뿐 ⇒ 역할이 다르다
refresh는 유효기간이 긺
- access token, refresh token 둘다 만료 ⇒ 에러 발생, 재로그인 필요
- access token 만료, refresh token 유효 ⇒ refresh token 검증, access 재발급
- access token 유효, refresh token 만료 ⇒ access token 검증, refresh 재발급
- access token, refresh token 유효 ⇒ 동작
초기 로그인시 둘다 발급하고 위와 같은 절차에 따라 동작
보통 access token은 세션, refresh는 쿠키에 저장한다고 AI피셜
리액트에서 JS API 연결하기
- useEffect를 통해서 API 다루고 그걸 window객체로서 접근해서 받는게 일반적
- ts환경에서는 있으면 타입정의가 안되니 declare를 통해 사전에 정의해두자
interface KakaoMaps {
maps: {
load: (callback: () => void) => void;
services: {
Status: {
OK: string;
ZERO_RESULT: string;
ERROR: string;
};
Geocoder: new () => Geocoder;
};
};
}
이런식
리액트 쿼리는 쿼리 키 비교할떄 참조값이 아닌 값의 깊은 비교를 통해 비교함 다른 참조값 같은 값 ⇒ 같은 키 임
리액트 쿼리를 사용할 때, 데이터 의존적 구조
리액트 쿼리로 A 데이터 받고 그 A 데이터에 의존한 B 데이터 다시 받아오는 구조는 안전한가?
⇒ 응 안전해~ 리액트 쿼리는 의존 요청 패턴 처리하도록 설계되어 있어
다만 enabled 옵션을 반드시 활용해야함, 키 값이 준비될떄까지 API 실행을 막기떄문
메모이제이션은 언제 사용할까?
1) 자식에게 props 전달됨?
➡ 잠재적으로 useCallback 필요.
2) 그 자식이 렌더링 비용이 큰 컴포넌트인가?
(BottomSheet, Modal, Item 리스트, 차트 등)
➡ useCallback 사실상 필요.
3) 자식이 React.memo 등을 사용할 가능성이 있는가?
➡ 향후 유지보수/확장까지 고려하면 useCallback 추천.
4) 단순한 자식이고 memo로 감쌀 일도 절대 없고 렌더링도 가볍다?
➡ 필요 없음.
메모이제이션은 말 그대로 usCallback, useMemo와 같이 각각 함수와 값을 캐싱해서 의존값이 달라질 때 까지 요청을 최소화 해 최적화 하는 것
작성한 함수라 프롭스로 전달돼? 그러면 useCallback 준비, 그리고 그게 렌더링이 크다? useCallback 사용
자식이 useMemo를 사용한다?, 그러면 useCallback
암기 하지말고 이해 하자.