패키지, 저장소 및 앱 카테고리 검색

패키지 상세v0.1.16

flutter_requery

비동기 데이터를 가져오고 캐시하며 무효화하기 위한 플러터 라이브러리입니다.

AndroidiOSWebmacOSWindowsLinux
30일 다운로드
425
좋아요
52
Pub 점수
150

패키지 설치

flutter pub add flutter_requery

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

Flutter Requery는 Flutter 애플리케이션에서 비동기 데이터 관리를 간소화하기 위해 설계된 가벼운 라이브러리입니다. 최소한의 반복 코드로 데이터 가져오기, 캐싱, 데이터 무효화를 내장 지원합니다. 패키지는 Flutter의 반응형 생태계와 원활하게 통합되어 네트워크 요청과 로컬 데이터에 대한 효율적인 상태 처리를 가능하게 합니다. Android, iOS, Web, macOS, Windows, Linux 등 여러 플랫폼을 지원하여 신뢰할 수 있는 데이터 동기화 및 캐시 제어가 필요한 크로스플랫폼 프로젝트에 적합합니다.

사용 사례

  • 자동 캐싱을 사용하여 API 데이터 가져오기
  • 업데이트 시 캐시된 데이터 무효화
  • 네트워크 요청의 상태 관리
  • 화면 간에 데이터 동기화
  • 오프라인 시나리오 처리
  • 중복 네트워크 호출 줄이기

주요 기능

  • 자동 데이터 캐싱
  • 캐시 무효화 전략
  • 반응형 데이터 스트림
  • 최소한의 보일러플레이트
  • 크로스 플랫폼 호환성
  • async/await 패턴 지원

적합한 대상

  • 지속적인 데이터 검색이 필요한 앱
  • 자주 API 상호작용이 있는 프로젝트
  • 간단한 상태 관리를 찾는 개발자
  • 크로스 플랫폼 플러터 앱
  • 네트워크 오버헤드를 줄이려는 팀

고려 사항

  • 데이터 가져오기 및 캐싱 사용 사례에 한정
  • 반응형 프로그래밍에 대한 이해가 필요합니다
  • 데이터 외 복잡한 상태 관리에는 적합하지 않습니다

원본 README

연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.

Flutter library for fetching, caching and invalidating asynchronous data

Quick Features

  • Fetch asynchronous data
  • Data invalidation
  • Optimistic response
  • Reset cache

Motivation

How to do API calls in Flutter? Probably, majority would answer by using Dio.
But the real question would be, how to integrate API calls in Flutter arhitecture seamless? One way would be to use FutureBuilder or maybe Bloc like most of the community do.

The thing is, both FutureBuilder and Bloc have flaws.
For example, FutureBuilder is too simple. It does provide status of your query, but communicating with some FutureBuilder is impossible outside of the scope of the current screen.
Problem with Bloc is that will include so many boilerplate code for a simple API call but again, talking to the Bloc is impossible from other screens. Bloc should be number one choice for complicated workflows, but what if you don't have any complex business logic?

flutter_requery to the rescue!

Example

Let's start with this simple example.

/// define data and cache key
final List<String> data = ["Hello"];
final String cacheKey = 'strKey';

/// simulates API call, therefore response is delayed
Future<List<String>> _getData() async {
  await Future.delayed(Duration(seconds: 1));
  return data;
}

/// later, used in the build method
Query<List<String>>(
  cacheKey,
  future: _getData,
  builder: (context, response) {
    if (response.error != null) {
      return Text('Error');
    }
    if (response.loading) {
      return Text('Loading...');
    }
    final children = response.data.map((str) => Text(str)).toList();
    return ListView(
      children: children
    );
  },
);

/// and later when you want to invalidate your data
void _onPress() async {
  await Future.delayed(Duration(seconds: 1));
  data.add("World");
  queryCache.invalidateQueries(cacheKey);
}

And that's the gist of it. You can find complete example on pub.dev.

Usage

Cache key

Every query needs a cache key.
Under this key your data will be stored in cache. It can be string, int or list of strings and ints.

/// good
const k1 = 'myKey';
const k2 = 1;
const k3 = ["data", 1]

/// bad
const k1 = 1.0;
const k2 = true;
const k3 = ["data", true];

Idea behind having keys specified as list is that you can invalidate your queries more intelligently.
Take a look at invalidation chapter for more details.

Query

Once the cache key is defined, next step is to write the query.
Query takes 3 arguments:

  • cacheKey - look here for more info.
  • future - async action which will be executed.
  • builder - follows the Flutter builder pattern. First parameter is BuildContext followed by QueryResponse object.

QueryResponse manages query status. It also has 3 properties:

  • data - response received from the future or null if the exception occured.
  • loading - boolean, true if the query is running. Otherwise, it's false.
  • error - represents an error received from the future. If the future was successful, error will be null.
// use Query widget in the build method
Query<List<String>>(
  'myCacheKey',
  future: ()async {
    await Future.delayed(Duration(seconds: 1));
    return ["Hello"]
  }
  builder: (context, QueryResponse response) {
    /// error state
    if (response.error != null) {
      return Text('Error');
    }
    /// loading state
    if (response.loading) {
      return Text('Loading...');
    }
    final children = response.data.map((str) => Text(str)).toList();
    return ListView(
      children: children
    );
  },
);
Invalidation

Data invalidation can come in two different forms.
You can either afford to wait for the API response or you simply need to show the newest data as soon as possible. If you are interested in following, check the next chapter.

Waiting for the API response is more common and flutter_requery supports this by using the queryCache instance. It's global and already defined by the library. Invalidate your query by passing the cache keys.

// invalidates strKey query
queryCache.invalidateQueries('strKey');

// support for bulk invalidation
queryCache.invalidateQueries(['strKey1', 'strKey2']);

// if your keys are lists, end result would be similar to
queryCache.invalidateQueries([
  ['strKey', 1],
  ['strKey2', 2]
]);

Once query is invalidated, every Query widget subscribed for that query will execute future again and rebuild its children with the new data.

For cache-level invalidation use:

// invalidate every query stored in cache
queryCache.invalidateAll()

Invalidation works in pair with the keys defined as lists. Cache keys defined as list must be looked upon in a hierarchical manner where the list elements defined before are ancestors of the elements that come after. For example:

// requests is ancestor of 1
const key1 = ["requests", 1]

Reasoning behind this is to support hierarchical invalidation. Sometimes it can get cumbersome managing invalidations and therefore developer can decide to cleverly name keys to support this. For example:

const k1 = ["requests", 1]
const k2 = ["requests", 2]
const k3 = "requests"

// without hierarchical invalidation you need to call
queryCache.invalidateQueries([
  ["requests", 1], ["requests", 2], "requests"
]);

// but with hierarchical invalidation you only need to call
queryCache.invalidateQueries("requests");
Optimistic response

Sometimes waiting period for the API response to be available is too long. Therefore you can immediately update the cache data and rebuild your widget tree by using the optimistic response. Make sure to remove await keyword before the API call since this will block the thread.

  queryCache.setOptimistic("requests", [...oldData, newData]);
Reset

In short, reset can be explained as cache-level invalidation without rebuilding the widget tree.
Also, async actions won't be ran immediately but only when the new Query widget is mounted or the cacheKey has changed. This is particularly useful for the log out action.

queryCache.reset();

Summary

API Description
Query Flutter widget used for data-fetching operations.
queryCache.invalidateQueries Invalidates query specified by cache key and rebuilds the widget tree.
queryCache.invalidateAll Invalidates every query stored in cache and rebuilds the widget tree.
queryCache.setOptimistic Set cache data manually and rebuild the widget tree.
queryCache.reset Invalidates every query stored in cache without rebuilding the widget tree.

카테고리

소스 저장소

이 패키지를 사용하는 프로젝트

아직 데이터가 없습니다.