랜더링 순서: 코드 위~아래 return 까지 내려갔다가 (useEffect 제외) -> 최초 랜더링 완료 후, useEffect 실행 -> useEffect 안에 getTodos 호출 실행 -> getTodos 함수 실행 -> 동기적으로 axios를 이용해 db 로부터 데이터를 가져오기 -> todos 상태(state) 변경 -> ...
=> 1번과 2번이 서로 다른 query key 인 이유는 배열로 이루어진 query key에는 요소의 순서가 중요하기 때문에 서로 다름을 가르는 기준이 되기때문이다.
UseQuery의 두번째 인자 :Query Functions
Query Functions은 promise 객체를 return 한다.
그리고 그 promise는 resolve 또는 error를 반환한다.
오류가 발생한 경우 -> 그에 맞는 적절한 오류 처리 관련 로직을 삽입해서 처리를 해야한다. axios, fetch, graphql 중 어떤 방법을 이용하던지 적절한 오류 처리를 통해 사용자가 혼란에 빠지지 않도록 해줘야한다. try ~ catch
UseQuery의 결과물 (=반환값 return)
usequery의 반환값은 객체이다.
그 객체 안에는 isLoading, isError, isSuccess, data 등이 들어있고
구조분해할당을 통해 꺼내 쓰면 용이하다.
호출시작시, isLoading=true
조회 결과 오류시 isError=true, isLoading=false (error 객체를 통해 좀 더 상세한 오류 내용을 확인할수있음)
조회 결과 정상시 isSuccess=true, isLoading=false. (data 객체를 통해 좀 더 상세한 조회 결과를 확인할 수 있음)
Mutations
- useMutation(비동기함수, { onSuccess : () => {}})
- mutation을 사용할 때는 mutation.mutate() 안에 들어가는 인자는 한 개의 변수 또는 한개의 객체만 들어갈 수 있다.
mutation.mutate(newTodo);
이 객체는 4 가지의 상태를 가진다.
{
isIdle:
isLoading:
isError:
isSuccess: data {...}
}
React Query의 라이프사이클
캐시 데이터의 라이프사이클 active = 캐시 데이터가 화면에서 사용되고 있다는 뜻 inactive = 캐시 데이터가 화면에서 사용되지 않고 있다는 뜻
1. query function을 통해서 fetching으로 db로부터 데이터를 받아오면, 그 데이터는 fresh 또는 stale이라는 상태를 갖게 된다. 2. fresh = 더 이상 새거가 필요하지 않다. 이미 uptodate 되어 있는 상태. -> query function 실행 시킬 필요 없음. 3. stale = 헌 것. outdated 된 상태. -> 계속해서 query function 실행 시키면서 db로부터 데이터를 받아와야 한다.
inactive 상태가 어느정도 되면 cacheTIme 만료로 garbage collector에 의해 deleted (삭제)가 된다.
default config (기본설정) ** stale time : 유통기한과 같다. stale time이 0 이 되면 'stale' 상태가 된다. 보통 디폴트값은 0 이고, 만약 설정을 해주고 싶다면 db.json 에서 아래와 같이 설정해줄 수 있다. stale time 이 있다면, fresh 하기때문에 더 이상 서버에 요청하지 않는다. **refetchOnMount: true => mount했을 때 refetch 해라! 디폴트는 true 이다. (예시: 다른페이지에 갔다가 다시 홈화면으로 왔을 때 다시 fetch를 해서 데이터를 가져오냐 아니냐) **refetchOnWindowFocus: true => 브라우저를 클릭할 때 refetch가 되는 것(true), 안되게 막는것(false). 디폴트는 true.
** refetchOnReconnect: true => Network 가 끊겼다가 재연결 되었을 때 stale data를 refetch 자동 실행. 디폴트는 true.
** cacheTime: 5분 (1000 * 60 * 5 ms) => 사용하지 않는 캐시데이터를 언제 삭제할 것인지를 정해주는 것. 사용하지 않는다는 것, 상태가 inactive 상태! 디폴트는 5분. 5초로 설정한 예시 코드 **retry: 3 => 재시도를 총 3번까지 한다. 서버상태가 항상 정상적일 순 없다. 따라서 불안정한 상태일때 브라우저에 바로 에러를 띄우는게 아니라 3번까지는 서버에 재요청을 한다는 뜻. 디폴트는 3회.
staleTime VS cache time
staleTIme = 얼마의 시간이 흐른 뒤에 stale(헌 것으로) 취급할 건지 (default: 0)
cacheTime = 사용하지 않는 데이터를 언제 삭제 할 것인지, inactive 된 이후로 메모리에 얼마만큼 있을건지 (default: 5분, cacheTime 0되면 삭제처리)
staleTime 과 stale / fresh의 관계
staleTime > 0 이면, fresh data
staleTime = 0 이면, stale data
" 하나의 쿼리 인스턴스(=하나의 query key =각각의 캐시데이터)마다 위와 같은 Lifecycle을 가진다. "
isLoading vs isFetching
isLoading
- 캐시 context 안에 아무것도 없었을 때, isLoading이 true가 된다. (캐시데이터가 있을 경우 isLoading=false, isFetching =true)
- 새로운 캐시 데이터를 서버에서 받고 있는 지 여부.
isFetching
- 캐시 context 안에 데이터가 있던지 없던지 상관없이, 서버에서 데이터를 받고 있는지 여부. query function으로부터 서버에서 데이터를 받고 있는지의 여부. 즉, query funciton이 실행되는 지의 여부.
생각해보기
Q. 메인페이지와 상세페이지가 모두 useQuery(”todos”, getTodos) 를 가질 때, 메인페이지 → 상세페이지 → 메인페이지 순으로 이동할 때 메인페이지 재 마운트 시의 isLoading, isFetching 의 콘솔로그값은?
적용 예제 (2) : Dependent Queries (useQuery 2개 이상이며 실행순서 설정 필요할 때)
// Dependent Query 예제 (순차적 query 실행)
// Get the user
const { data: user } = useQuery({
queryKey: ['user', email],
queryFn: getUserByEmail,
})
const userId = user?.id // optional Chaining : user가 없으면 undefined, 있으면 id 까지 접근
// Then get the user's projects
const {
status,
fetchStatus,
data: projects,
} = useQuery({
queryKey: ['projects', userId],
queryFn: getProjectsByUser,
// The query will not execute until the userId exists
enabled: !!userId //userId가 참이면 그때서야 queryFn를 실행시킨다는 뜻
})
// 여기서 !!userId 는 Boolean(userId)와 같습니다.
// 만약 userId가 undefined라면, !!userId는 false 이다.
userId가 참이면 그때서야 queryFn를 실행시킨다는 뜻
2. select
import { useQuery } from 'react-query'
function User() {
const { data } = useQuery(['user'], fetchUser, {
select: (user) => user.username,
})
return <div>Username: {data}</div>
}
cache context 안에 fetchuser에 의한 값을 select의 매개변수로 넣어줄 수 있다.
queryFn 에 의해 리턴된 값을 변형시킨 후에 useQuery 의 리턴 data로 넘겨줌.