command_hooks 0.0.2 copy "command_hooks: ^0.0.2" to clipboard
command_hooks: ^0.0.2 copied to clipboard

A Flutter Hooks library providing Result-like async primitives, Commands for event handlers, and utilities for managing async operations.

command_hooks - a Flutter Hooks library for writing async code #

dependencies:
  command_hooks: ^0.0.1

Installation #

This package has a peer dependency on Flutter and flutter_hooks:

dependencies:
  command_hooks: ^0.0.1
  flutter_hooks: ^0.21.3

Commands are a new primitive for writing Flutter widgets that invoke asynchronous methods easily. If you've ever tried to write a bunch of ugly useEffect/useState code to manage button presses, this is much better and easier!

Commands also automatically ensure that only one invocation of the method is running concurrently, and makes it really easy to write pending and error states.

Here's an example:

class PokemonLookupPage extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final pokemon = useState("");

    // useCommand returns a CommandState with invoke, current, reset,
    // and convenience getters like isLoading, hasError, hasData, data, error
    final searchCmd = useCommand(() async {
      if (pokemon.value.isEmpty || pokemon.value.length < 3) {
        return <Pokemon>[];
      }

      return await fetchPokemonByName(pokemon.value);
    }, [pokemon.value]);

    // Map our pending result to Flutter widgets
    final searchResult = searchCmd.current.mapOrElse(
      ok: (results) => results != null && results.isNotEmpty
          ? Column(
              children: [
                Text('Pokemon found!', style: Theme.of(context).textTheme.headlineMedium),
                ...results.map((r) => ListTile(
                  title: Text(r.name),
                  subtitle: Text(r.information),
                )),
              ],
            )
          : null,
      err: (e) => Text('Failed to fetch Pokemon!', style: Theme.of(context).textTheme.headlineMedium),
      pending: () => CircularProgressIndicator(),
    );

    return Scaffold(
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            TextField(
              onChanged: (value) => pokemon.value = value,
              decoration: InputDecoration(labelText: 'Pokemon name'),
            ),
            SizedBox(height: 16),
            ElevatedButton(
              // Use the isLoading convenience getter
              onPressed: searchCmd.isLoading ? null : searchCmd.invoke,
              child: Text('Search for Pokemon'),
            ),
            SizedBox(height: 16),
            if (searchResult != null) searchResult,
          ],
        ),
      ),
    );
  }
}

AsyncSnapshot Extensions (Result-like API) #

This library extends AsyncSnapshot with a Result-like API similar to Kotlin and Rust's Result class, but with an additional "pending" state. This makes it perfect for async operations in UIs!

Factory Functions

  • ok(value) - Creates an AsyncSnapshot with a successful value.
  • err(error) - Creates an AsyncSnapshot representing an error.
  • pending() - Creates a pending AsyncSnapshot.
  • fromFuture(future) - Boxes a Future into an AsyncSnapshot, capturing errors.

Instance Methods

  • isOk() - Checks if the snapshot has completed successfully.
  • isErr() - Checks if the snapshot has an error.
  • isPending() - Checks if the snapshot is pending (waiting or none state).
  • isUndefined() - Checks if the snapshot is ok but the data is null.
  • okOr(defaultValue) - Gets the Ok value or a default value if not Ok.
  • expect() - Expects the snapshot to be Ok and returns the value, throwing if not.
  • expectErr() - Expects the snapshot to be an Error and returns the error, throwing if not.
  • map(fn) - Transforms the snapshot by applying a function to the Ok value.
  • mapErr(fn) - Transforms the snapshot by applying a function to the Error value.
  • mapOrElse(ok:, err:, pending:) - Unboxes the snapshot by applying different functions based on state. Extremely useful for building UIs!

What else does this do? #

This library is also a grab-bag of all the code I keep copy-pasting into different projects, but this time, it's all documented:

Hooks #

  • useObservable(streamFactory, keys) - A Flutter hook that consumes a Stream and returns its latest result as an AsyncSnapshot.
  • useCancellableFuture(block, keys) - A Flutter hook that consumes a cancellable Future and returns its result, respecting dependencies similar to useEffect.
  • useCommand(block, keys) - Creates a Command for handling async operations in event handlers with automatic debouncing. Returns a CommandState with invoke, current, reset, and convenience getters (isLoading, hasError, hasData, data, error, stackTrace).
  • useAsyncCallbackDedup(block, keys) - Creates a debounced async callback that only runs one instance at a time.
  • useExplicitRender() - Provides explicit re-rendering functionality with a dependency value and rerender function.

Future Utilities #

  • fromCancellableFuture(block) - Converts a Future factory (with cancellation token) to a Stream, allowing cancellation.
  • retryFuture(func, retries:) - Retries a Future-returning function a specified number of times.
  • asyncMap(items, selector, maxConcurrency:) - Maps a list using an async selector with concurrency control.
  • asyncReduce(items, selector, seed) - Like fold, but each step is asynchronous.
0
likes
160
points
97
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter Hooks library providing Result-like async primitives, Commands for event handlers, and utilities for managing async operations.

Repository (GitHub)
View/report issues

Topics

#flutter #hooks #async #state-management

Documentation

API reference

License

MIT (license)

Dependencies

cancellation_token, flutter, flutter_hooks, rxdart

More

Packages that depend on command_hooks