fuery_hooks 1.4.4 copy "fuery_hooks: ^1.4.4" to clipboard
fuery_hooks: ^1.4.4 copied to clipboard

Hooks for Fuery: render cached server data with useQuery, useInfiniteQuery, useMutation, and useQueries in a flutter_hooks HookWidget.

Fuery: server state for Flutter

Hooks for Fuery: render cached server data from inside build, in a flutter_hooks HookWidget.

Fuery is built the Flutter way. Queries are defined outside build, and widgets render them: builders for UI and listeners for side effects, in the shape of StreamBuilder. And fuery depends on nothing beyond Dart and Flutter.

fuery_hooks is for developers who prefer hooks, a style many know from web development. It is a package of its own because it depends on flutter_hooks, so only apps that choose hooks get that dependency. It renders the same queries with one call per query, and no builders:

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

class TodoListScreen extends HookWidget {
  const TodoListScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final todos = useQuery(todosQuery);
    return switch (todos) {
      QueryResult(:final data?) => TodoList(data),
      QueryResult(:final error?) => Text('$error'),
      _ => const CircularProgressIndicator(),
    };
  }
}

The queries, mutations, and client are Fuery's own, so a screen written with hooks and a screen written with widgets share one cache and one request.

Read the hooks guide → · Fuery documentation →

Install #

flutter pub add fuery_hooks flutter_hooks

fuery_hooks re-exports fuery, so package:fuery_hooks/fuery_hooks.dart and package:flutter_hooks/flutter_hooks.dart are the only imports you need.

Hooks #

Hook Returns
useQuery(query) The latest QueryResult. refetch() is on the result.
useInfiniteQuery(query) The latest InfiniteQueryResult. fetchNextPage() is on the result.
useMutation(mutation) The latest MutationResult. mutate(...) is on the result.
useQueries(queries) The results of a list of queries of one data type, in order.
useQueryClient() The client the hooks use, for invalidateQueries and setData.

Each rebuilds the widget when its result changes, and needs no type arguments: todos above is a QueryResult<List<Todo>> because api.getTodos() returns a Future<List<Todo>>.

One query that needs another #

Hooks return the result of this moment; they don't wait. A query that needs a value from another one turns itself off until the value exists:

Query<List<Post>> postsQuery(int? userId) => Query(
      queryKey: ['posts', userId],
      queryFn: (_) => api.getPosts(userId!),
      enabled: userId != null,
    );

final user = useQuery(userQuery);
final posts = useQuery(postsQuery(user.data?.id));

The first build has no user, so posts is pending and fetches nothing. When the user arrives, the widget rebuilds, posts gets the key ['posts', 7], and it fetches in that same build.

Changing data #

final addTodo = useMutation(addTodoMutation);

ElevatedButton(
  onPressed: addTodo.isPending ? null : () => addTodo.mutate('Buy milk'),
  child: const Text('Add'),
)

A NoVariablesMutation runs with mutate(null), as from a MutationBuilder:

final logout = useMutation(logoutMutation);

TextButton(
  onPressed: () => logout.mutate(null),
  child: const Text('Log out'),
)

For a side effect of one call, such as a snackbar, pass MutateOptions to mutate. The request itself still finishes when the widget goes away. For a definition, the callbacks of its calls are dropped then. A shared observer is left alone and still runs them, so check context.mounted in them.

Rules #

  • Pass a definition. A Query or a Mutation can be a top-level value or be built in build: the hook keeps one observer for it and updates its options, so a new key shows in the same frame.
  • Don't call .observe() in build. A new query observer every build subscribes and fetches again, and a new mutation observer starts idle. In debug builds the hook prints a warning once per key.
  • Run side effects in a listener. For a snackbar or navigation, wrap what the widget builds in a QueryListener with the same query. useEffect and useValueChanged run during the build, where those calls fail.
  • Watch the client with a memoized stream: useStream(useMemoized(() => client.watch(selector), [client])). A new stream every build rebuilds the widget on every frame.
  • The client is the one a FueryProvider above provides, or Fuery.client, and useQueryClient() returns it. A shared observer keeps the client it was created with instead.

Everything else, from keys and freshness to persistence and devtools, is Fuery's. See the documentation.

0
likes
0
points
47
downloads

Documentation

Documentation

Publisher

unverified uploader

Weekly Downloads

Hooks for Fuery: render cached server data with useQuery, useInfiniteQuery, useMutation, and useQueries in a flutter_hooks HookWidget.

Homepage
Repository (GitHub)
View/report issues

Topics

#hooks #server-state #cache #state-management #offline

License

unknown (license)

Dependencies

flutter, flutter_hooks, fuery

More

Packages that depend on fuery_hooks