주어진 시간에 대해 시스템을 나타내는 것
언제든지 변경될 수 있음
문자열, 배열, 객체 등의 형태로 응용 프로그램에 저장된 데이터
개발자에게 상태 : 관리해야 하는 데이터들
UI/UX의 중요성과 함께 프로덕트의 규모가 커짐, FE에서 수행하는 역할이 늘어남
관리하는 상태가 많아짐
상태를 관리하는 방법에 대한 것
상태들은 시간에 따라 변화함
REact는 단방향 바인딩, Props Drilling 이슈가 존재
Redux나 MobX 같은 라이브러리를 활용해 해결하는 방법도 있음
Client State | Server State |
---|---|
Client에서 소유, 온전히 제어 가능 | Client가 아닌 다른 원격의 공간에서 관리되고 유지 |
초기값 설정이나 조작에 제약사항 없음 | Fetching/Updating에 비동기 API 필요 |
다른 사람과 공유되지 않음. Client 내에서 UI/UX흐름이나 사용자 인터렉션에 따라 변할 수 있음 | 다른 사람과 공유됨. 사용자가 모르는 사이 변경될 수 있음 |
항상 Client에서 최신 상태로 관리 | 잠재적으로 "out of date"가 될 가능성이 있음 |
공식문서
fetch, caching, update 등의 비동기 로직을 지원하는 fetching 라이브러리.
zero-config로 즉시 사용 가능(config로 커스텀 가능)
function App () {
return <QueryClientProvider client={queryClient}>...</QueryClientProvider>
}
import {
QueryClient,
QueryClientProvider,
useQuery,
} from "@tanstack/react-query";
const queryClient = new QueryClient();
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
);
}
function Example() {
const { isLoading, error, data, isFetching } = useQuery({
queryKey: ["repoData"],
queryFn: () =>
axios
.get("https://api.github.com/repos/tannerlinsley/react-query")
.then((res) => res.data),
});
if (isLoading) return "Loading...";
if (error) return "An error has occurred: " + error.message;
return (
<div>
<h1>{data.name}</h1>
<p>{data.description}</p>
<strong>👀 {data.subscribers_count}</strong>{" "}
<strong>✨ {data.stargazers_count}</strong>{" "}
<strong>🍴 {data.forks_count}</strong>
<div>{isFetching ? "Updating..." : ""}</div>
<ReactQueryDevtools initialIsOpen />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.createRoot(rootElement).render(<App />);
실제로 사용할 때는 queries 파일 분리도 추천
const fetchOrderREsult = useFetchOrder(orderNo,{
onSuccess:fetchOrderResultData => {
// onSuccess 로직
},
onError:error=>{
// onError 로직
},
})
const fetchDeliveryStatusResult = useFetchDeliveryStatus(orderNo,{
refetchInterval:isPollingActive ? 5000 : false,
onSuccess:fetchOrderResultData => {
// onSuccess 로직
},
onError:error=>{
// onError 로직
},
})
query가 여러 개일 경우, 알아서 잘 작동 됨!
function App () {
const usersQuery = useQuery('users', fetchUsers)
const teamsQuery = useQuery('teams', fetchTeams)
...
}
// 동적으로 작동하려면 다른 방법을 사용해야 함
보통 GET으로 받아온 대부분의 API에 사용
데이터 Fetching용(CRUD의 R에서만 사용)
function App() {
const info = useQuery('todos', fetchTodoList);
// (Query Key, Query Function)
}
// String 형태
useQuery('todos', ...)
// Array 형태
useQuery(['todo',5], ...)
Promise를 반환하는 함수(데이터를 resolve하거나 error을 throw)
useQuery('fetchOrder', ()=>fetchOrder(orderNo), options)
데이터 updating시 사용
데이터 생성/수정/삭제용(CRUD중 CUD에서 모두 사용)
const mutation = useMutation(newTodo => {
return axios.post('/todos', newTodo)
})
useQuery보다 더 심플하게 Promise 반환 함수만 있으면 됨
(Query Key를 넣어주면 devtools에서 볼 수 있음)
queryClient를 통해 invalidate 메소드를 호출해 사용
// cache에 있는 모든 쿼리
queryClient.invalidationQueries()
// todos로 시작하는 키의 모든 쿼리
queryClient.invalidationQueries('todos')
해당 Key를 가진 query는 stale 취급
현재 rendering 되는 query들은 백그라운드에서 refetch
Query 상태흐름
화면에 있다가 사라지는 query
- fetching -[staleTime>0]-> fresh(staleTime이 만료되기 전까지) -[staleTime 만료]-> stale(스크린에서 사용되는 동안) -[스크린에서 사용X]-> inactive(cacheTime이 만료되기 전까지) -[cacheTime 만료]-> deleted(GC처리)
- fetching -[staleTime = 0]-> stale ...
화면에 있다가 없다가 하는 query- active상태의 query는 fetching과 stale 상태를 반복(stale->fetching)
(refetch이벤트가 발생하거나 Mount, window focus등의 옵션에 따른 트리거 발생)
어떻게 Server State를 전역상태처럼 관리할 수 있는지
// Components A
function App(){
const info = useQuery('todos', fetchTodoList)
}
// Components B
function App(){
const info = useQuery('todos', fetchTodoList)
}
// stale이 지속되는 동안에는 A마운트 되고 B가 마운트 되어도 API 호출이 발생하지 않음
QueryClient 내부적으로 Context 사용
Client store : Client State만 남아 목적에 맞고 심플해짐
Server State : React Query와 함께 간단해짐
Component : 길이가 더 길어짐
useQuery를 이용해 불러온 server state를 이용해 액션을 생성해야 하는 경우
어느단계에서 server state를 참조하는지
-> option의 onSucess에서 참조(서버 상태는 서버 상태로 관리, 클라이언트 상태랑 디팬던시가 생기는건 좋지 않음)
개발 할 때 cacheTime이나 staleTime 등을 변경해서 사용하는 경우
광고를 한시간동안 갱신하는 경우, staleTime을 1시간으로 주면 그 1시간동안은 기존에 가지고 있던 데이터를 보여줌
(질의응답 파트 시간이 나면 계속 듣기 1:38:15 ~)