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

GitHub 저장소KRTirtho/fl-query

fl-query

Flutter를 위한 비동기 데이터 가져오기 및 데이터 무효화 라이브러리

fl-query 프로젝트 이미지
스타
68
포크
12
최근 푸시(UTC)
2026. 1. 31.
프로젝트 상태
보관됨

원본 README

아래는 영문 원문 스냅샷입니다. 최신 내용은 GitHub에서 확인하세요.

"Fl-Query Logo"

Fl-Query

Asynchronous data caching, refetching & invalidation library for Flutter. FL-Query lets you manage & distribute your async data without touching any global state

Fl-Query makes asynchronous server state management a breeze in flutter

Features

  • Async data caching & management
  • Smart + effective refetching
  • Optimistic updates
  • Automatically cached data invalidation & unneeded query/mutation garbage collection
  • Infinite pagination via InfiniteQuery
  • Lazy persistent cache (Uses hive for persisting query results to disk) (optional)
  • Easy to write & understand code. Follows DRY (Don't repeat yourself) convention
  • Compatible with both vanilla Flutter & elite flutter_hooks

Installation

Regular installation:

$ flutter pub add fl_query

For elite flutter_hooks user (Welcome to the flutter cool community btw😎)

$ flutter pub add flutter_hooks fl_query_hooks

Docs

You can find the documentation of fl-query at https://fl-query.krtirtho.dev/

Basic Usage

Initialize the cache databases in your main method

fl-query uses hive for persisting data to disk

void main()async {
  WidgetsFlutterBinding.ensureInitialized();
  await QueryClient.initialize(cachePrefix: 'fl_query_example');
  runApp(MyApp());
}

In MyApp Widget's build method wrap your MaterialApp with with QueryClientProvider widget

  Widget build(BuildContext context) {
    return QueryClientProvider(
      child: MaterialApp(
        title: 'Fl-Query Example App',
        theme: ThemeData(
          useMaterial3: true,
          primarySwatch: Colors.blue,
        ),
        home: const MyHomePage(),
      ),
    );
  }

Let's write use a Query now FL-Query provides a QueryBuilder widget that creates and listens to the specified Query and re-runs the builder function whenever there's an update

It has 2 required parameters(unnamed) key & builder

class MyApp extends StatelessWidget{
    MyApp({super.key});

    @override
    build(context){
      return QueryBuilder<String, dynamic>(
        'hello',
        () {
          return Future.delayed(
              const Duration(seconds: 6), () => 'Hello World!');
        },
        initial: 'A replacement',
        jsonConfig: JsonConfig(
          fromJson: (json) => json['data'],
          toJson: (data) => {'data': data},
        ),
        onData: (value) {
          debugPrint('onData: $value');
        },
        onError: (error) {
          debugPrint('onError: $error');
        },
        builder: (context, query) {
          if (query.isLoading) {
            return const Center(
              child: CircularProgressIndicator(),
            );
          } else if (query.hasError) {
            return Center(
              child: Text(query.error.toString()),
            );
          }
          return Center(
            child: Text(query.data ?? "Unfortunately, there's no data"),
          );
        },
      );
    }
}

And if you're using flutter_hooks you got that too

class MyApp extends HookWidget{
    MyApp({super.key});

    @override
    build(context){
      final query = useQuery<String, dynamic>(
        'hello',
        () {
          return Future.delayed(
              const Duration(seconds: 6), () => 'Hello World!');
        },
        initial: 'A replacement',
        jsonConfig: JsonConfig(
          fromJson: (json) => json['data'],
          toJson: (data) => {'data': data},
        ),
        onData: (value) {
          debugPrint('onData: $value');
        },
        onError: (error) {
          debugPrint('onError: $error');
        },
      );

      if (query.isLoading) {
        return const Center(
            child: CircularProgressIndicator(),
          );
      } else if (query.hasError) {
        return Center(
          child: Text(query.error.toString()),
        );
      }
      return Center(
        child: Text(query.data ?? "Unfortunately, there's no data"),
      );
    }
}

To master the fl-query follow the official blog at https://fl-query.krtirtho.dev/blog

Why?

The hell, why?

The main purpose of Fl-Query is providing the easiest way to manage the messy server-state part requiring the least amount of code with code reusability & performance This let's you focus more on those cool UI animations & transitions✨. Leave the boring stuff to fl-query

Q. Isn't FutureBuilder good?

No, of course not. Unless you're from 2013 or your app is a purely offline app

Q. So FutureProvider from riverpod or provider not enough?

Probably yes. Although riverpod@v2 has added a lot of caching related features but still optimistic updates, periodic refetching & disk persistence are missing. Let's not forget about infinite pagination, it's a nightmare😅. In case of provider, same story. It's a great package but it's not ideal for server-state management

Notice Board

We need some bada** coders to write tests and ruin our life🥲 100% coverage is our goal🙃

Kingkor Roy Tirtho GitHub avatar
GitHub 작성자

Kingkor Roy Tirtho ↗

Maxint Inc. (@maxint-app)Dhaka, Bangladesh
언어DartC++CMakeRubyHTMLCSwiftKotlinObjective-C

사용 중인 의존성

의존성 목록 1 개

프로젝트에 맞는 저장소를 선택하려면?

사용 목적에 따라 검색하고 개발 활동을 비교한 뒤 원본 저장소에서 요구 사항을 확인하세요.

  1. 이름, 작성자 또는 설명으로 검색하고 기술 주제로 범위를 좁힙니다.
  2. 스타, 포크, 최근 푸시를 함께 비교하세요. 스타는 관심의 지표이며 품질을 보장하지 않습니다.
  3. 사용하기 전에 GitHub에서 README, 라이선스, Issues를 확인하세요.

출처 및 관리

“A repository is the most basic element of GitHub.”

GitHub Docs — About repositories ↗