콘텐츠로 이동

Flutter의 서버 상태

서버 데이터에는 상태 클래스를 하나 더 두기보다 캐시가 필요해요. 캐시는 모든 화면에 같은 데이터를 주고, 로딩과 에러를 추적하고, 오래된 데이터를 다시 가져와요.

Flutter 앱이 보여주는 데이터는 대부분 할 일 목록, 프로필, 검색 결과 페이지처럼 서버에서 와요. 이 데이터는 앱이 소유한 상태와 다르게 동작해요.

  • 앱이 소유하지 않아요. 데이터는 앱에 알리지 않고 서버에서 바뀌어요.
  • 여러 곳에서 공유해요. 여러 화면이 같은 목록을 보여주고, 화면끼리 내용이 같아야 해요.
  • 늦게 도착하거나 아예 도착하지 않아요. 읽을 때마다 로딩 상태와 에러 상태가 있어요.
  • 시간이 지나면 오래된 데이터가 돼요. 1분 전에 가져온 목록이 지금은 틀릴 수 있어요.

어느 탭을 선택했는지 같은 앱 상태에는 이런 문제가 하나도 없어요.

앱 상태 서버 데이터
바꾸는 쪽 직접 작성한 코드 서버, 언제든지
원본이 있는 곳 앱 다른 곳
도착하는 시점 바로 나중에, 또는 도착하지 않음
오래된 데이터가 되는지 아니요 예

서버 데이터를 앱 상태와 같은 곳에 두면 캐시를 직접 만들어야 해요. 리포지토리 안의 캐시, 화면마다 두는 로딩 플래그, 새로고침 메서드, 서버에 쓸 때마다 무효화하는 코드, 두 화면이 동시에 요청할 때의 규칙이 모두 필요해요.

Fuery는 서버 데이터를 캐시 하나에 키로 나눠 둬요.

final todosQuery = Query(
queryKey: ['todos'],
queryFn: (_) => api.getTodos(),
);

이 정의 하나로 캐시가 이렇게 동작해요.

  • 키 하나에 사본 하나. ['todos']를 사용하는 화면은 모두 같은 캐시 항목을 읽어요.
  • 요청은 한 번에 하나. 데이터를 가져오는 동안 요청한 화면은 그 요청을 공유해요.
  • fresh 상태였다가 stale 상태로. 데이터는 staleTime 동안 fresh 상태예요. 기본값은 0이라서 데이터는 도착하자마자 stale 상태가 돼요.
  • 이전 데이터는 화면에 남아요. Fuery가 백그라운드에서 다시 가져오는 동안 화면은 이전 데이터를 계속 보여줘요.
  • 알아서 다시 가져와요. 화면이 stale 데이터를 사용하기 시작하거나 앱이 포그라운드로 돌아오면 Fuery가 그 데이터를 다시 가져와요. 연결 상태 소스가 있으면 네트워크가 다시 연결될 때도 다시 가져와요(네트워크가 다시 연결될 때).
  • 쓰고 나면 다시 가져와요. 뮤테이션 뒤에 ['todos']를 무효화하면 Fuery가 화면의 목록을 다시 가져와요.
  • 로딩과 에러가 데이터와 같이 와요. 결과에는 status, error, 그리고 isRefetching 같은 플래그가 있어요. 그래서 화면은 이 값을 직접 추적하지 않고 읽기만 해요.
  • 사용하지 않는 데이터는 메모리에서 사라져요. 어떤 화면도 사용하지 않는 데이터는 gcTime(가비지 컬렉션 시간, 기본값: 5분)이 지나면 Fuery가 제거해요. 기기에 저장한 데이터는 기기에 그대로 남아요.

캐시된 데이터가 거치는 단계와 단계마다 끝나는 조건은 쿼리 생명주기에 있어요.

캐시는 위젯 트리의 일부가 아니라 평범한 Dart 객체예요. 같은 쿼리가 세 곳에서 동작해요.

  • QueryBuilder가 쿼리를 렌더링해요.
  • Cubit이 todosQuery.observe()의 stream을 구독해요.
  • 스크립트가 client.query(todosQuery)를 await로 기다려요.

Fuery는 지금 사용하는 상태 관리를 대체하지 않아요. Cubit과 Bloc 안에서 쿼리를 사용하는 방법은 Bloc과 Cubit에 있어요.