asyncredux-flutter-hooks

star 238

Integrate AsyncRedux with the flutter_hooks package. Covers adding flutter_hooks_async_redux, using the useSelector hook, and combining hooks with AsyncRedux state management.

marcglasberg By marcglasberg schedule Updated 1/29/2026

name: asyncredux-flutter-hooks description: Integrate AsyncRedux with the flutter_hooks package. Covers adding flutter_hooks_async_redux, using the useSelector hook, and combining hooks with AsyncRedux state management.

Overview

The flutter_hooks_async_redux package provides a hooks-based API for accessing AsyncRedux state. If you prefer functional components with hooks over the widget-based StoreConnector pattern, this package lets you use hooks like useSelector and useDispatch to interact with the Redux store.

Installation

Add these dependencies to your pubspec.yaml:

dependencies:
  flutter_hooks: ^0.21.2
  async_redux: ^24.2.2
  flutter_hooks_async_redux: ^3.1.0

Then run flutter pub get.

Core Hooks

useSelector

Selects a part of the state and subscribes to updates. The widget rebuilds when the selected value changes:

String username = useSelector<AppState, String>((state) => state.username);

The distinct parameter (default true) controls whether the widget rebuilds only when the selected value changes.

Creating a Custom useAppState Hook

For convenience, define a custom hook that's pre-typed for your state:

T useAppState<T>(T Function(AppState state) converter, {bool distinct = true}) =>
    useSelector<AppState, T>(converter, distinct: distinct);

This simplifies state access throughout your app:

// Instead of:
String username = useSelector<AppState, String>((state) => state.username);

// Use:
String username = useAppState((state) => state.username);

useDispatch

Dispatches actions that may change the store state. Works with both sync and async actions:

class MyWidget extends HookWidget {
  @override
  Widget build(BuildContext context) {
    var dispatch = useDispatch();

    return ElevatedButton(
      onPressed: () => dispatch(IncrementAction()),
      child: Text('Increment'),
    );
  }
}

useDispatchAndWait

Dispatches an action and returns a Future<ActionStatus> that resolves when the action completes:

class MyWidget extends HookWidget {
  @override
  Widget build(BuildContext context) {
    var dispatchAndWait = useDispatchAndWait();
    var dispatch = useDispatch();

    Future<void> handleSubmit() async {
      // Wait for first action to complete
      await dispatchAndWait(DoThisFirstAction());
      // Then dispatch the second
      dispatch(DoThisSecondAction());
    }

    return ElevatedButton(
      onPressed: handleSubmit,
      child: Text('Submit'),
    );
  }
}

You can also check the action status:

var status = await dispatchAndWait(MyAction());
if (status.isCompletedOk) {
  // Action succeeded
}

useDispatchSync

Enforces synchronous action dispatch. Throws StoreException if you attempt to dispatch an async action:

var dispatchSync = useDispatchSync();
dispatchSync(MySyncAction()); // OK
dispatchSync(MyAsyncAction()); // Throws StoreException

Waiting and Error Hooks

useIsWaiting

Checks if an async action is currently being processed:

class MyWidget extends HookWidget {
  @override
  Widget build(BuildContext context) {
    var dispatch = useDispatch();
    var isLoading = useIsWaiting(LoadDataAction);

    return Column(
      children: [
        if (isLoading) CircularProgressIndicator(),
        ElevatedButton(
          onPressed: () => dispatch(LoadDataAction()),
          child: Text('Load'),
        ),
      ],
    );
  }
}

You can check by action type, action instance, or multiple types:

// By action type
var isWaiting = useIsWaiting(MyAction);

// By action instance
var action = MyAction();
dispatch(action);
var isWaiting = useIsWaiting(action);

// Multiple types - true if ANY are in progress
var isWaiting = useIsWaiting([BuyAction, SellAction]);

useIsFailed

Checks if an action has failed:

var isFailed = useIsFailed(MyAction);

if (isFailed) {
  return Text('Something went wrong');
}

useExceptionFor

Retrieves the UserException from a failed action:

var exception = useExceptionFor(MyAction);

if (exception != null) {
  return Text(exception.reason ?? 'Unknown error');
}

useClearExceptionFor

Gets a function to clear the exception state for an action:

var clearExceptionFor = useClearExceptionFor();

// Clear exception when user dismisses error
ElevatedButton(
  onPressed: () => clearExceptionFor(MyAction),
  child: Text('Dismiss'),
)

Complete Example

Here's a full example combining multiple hooks:

class UserProfileWidget extends HookWidget {
  @override
  Widget build(BuildContext context) {
    // Select state
    var username = useAppState((state) => state.user.name);
    var email = useAppState((state) => state.user.email);

    // Dispatch hooks
    var dispatch = useDispatch();
    var dispatchAndWait = useDispatchAndWait();

    // Loading and error state
    var isLoading = useIsWaiting(UpdateProfileAction);
    var isFailed = useIsFailed(UpdateProfileAction);
    var exception = useExceptionFor(UpdateProfileAction);
    var clearException = useClearExceptionFor();

    Future<void> handleUpdate() async {
      var status = await dispatchAndWait(UpdateProfileAction());
      if (status.isCompletedOk) {
        // Show success message
      }
    }

    return Column(
      children: [
        Text('Username: $username'),
        Text('Email: $email'),

        if (isLoading)
          CircularProgressIndicator(),

        if (isFailed && exception != null)
          Row(
            children: [
              Text(exception.reason ?? 'Update failed'),
              IconButton(
                icon: Icon(Icons.close),
                onPressed: () => clearException(UpdateProfileAction),
              ),
            ],
          ),

        ElevatedButton(
          onPressed: isLoading ? null : handleUpdate,
          child: Text('Update Profile'),
        ),
      ],
    );
  }
}

Hook Parameters Reference

Hook Accepts Returns
useSelector<St, T> Converter function Selected value of type T
useDispatch None Dispatch function
useDispatchAndWait None Function returning Future<ActionStatus>
useDispatchSync None Sync dispatch function
useIsWaiting Action type, instance, or list of types bool
useIsFailed Action type, instance, or list of types bool
useExceptionFor Action type, instance, or list of types UserException?
useClearExceptionFor None Clear function

Hooks vs StoreConnector

Choose hooks when:

  • You prefer functional widget patterns
  • You're already using flutter_hooks in your project
  • You want concise state access without view-model boilerplate

Choose StoreConnector when:

  • You want explicit separation between UI and state logic
  • You need the structured view-model pattern for testing
  • You're not using hooks elsewhere in your project

Both approaches work well with AsyncRedux - pick the one that fits your team's preferences.

References

URLs from the documentation:

Install via CLI
npx skills add https://github.com/marcglasberg/async_redux --skill asyncredux-flutter-hooks
Repository Details
star Stars 238
call_split Forks 39
navigation Branch main
article Path SKILL.md
More from Creator
marcglasberg
marcglasberg Explore all skills →