Claude-skill-registry asyncredux-provider-integration

Integrate AsyncRedux with the Provider package. Covers using provider_for_redux, the ReduxSelector widget, and choosing between StoreConnector and ReduxSelector approaches.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/asyncredux-provider-integration" ~/.claude/skills/majiayu000-claude-skill-registry-asyncredux-provider-integration && rm -rf "$T"
manifest: skills/data/asyncredux-provider-integration/SKILL.md
source content

Provider Integration with AsyncRedux

The

provider_for_redux
package bridges Provider and AsyncRedux, enabling you to use Provider's dependency injection with Redux state management.

Installation

Add the package to your

pubspec.yaml
:

dependencies:
  provider_for_redux: ^8.0.0

Setting Up AsyncReduxProvider

Replace

StoreProvider
with
AsyncReduxProvider
to expose three items to descendant widgets:

  • The Redux store (
    Store<AppState>
    )
  • The application state (
    AppState
    )
  • The dispatch method (
    Dispatch
    )
import 'package:provider_for_redux/provider_for_redux.dart';

void main() {
  final store = Store<AppState>(initialState: AppState.initial());

  runApp(
    AsyncReduxProvider<AppState>.value(
      value: store,
      child: MaterialApp(home: MyHomePage()),
    ),
  );
}

Accessing State with Provider.of

Access store components directly using standard Provider patterns:

// Access state (rebuilds on state changes)
final counter = Provider.of<AppState>(context).counter;

// Access dispatch (use listen: false for actions)
Provider.of<Dispatch>(context, listen: false)(IncrementAction());

// Access the store directly
final store = Provider.of<Store<AppState>>(context, listen: false);

ReduxConsumer Widget

ReduxConsumer
provides store, state, and dispatch in a single builder, simplifying access:

ReduxConsumer<AppState>(
  builder: (context, store, state, dispatch, child) {
    return Column(
      children: [
        Text('Counter: ${state.counter}'),
        Text('Description: ${state.description}'),
        ElevatedButton(
          onPressed: () => dispatch(IncrementAction()),
          child: Text('Increment'),
        ),
      ],
    );
  },
)

ReduxSelector Widget

ReduxSelector
prevents unnecessary rebuilds by selecting specific state portions. Only when selected values change does the widget rebuild.

Using a List (Recommended)

The simplest approach - explicitly list the properties that should trigger rebuilds:

ReduxSelector<AppState, dynamic>(
  selector: (context, state) => [state.counter, state.description],
  builder: (context, store, state, dispatch, model, child) {
    return Column(
      children: [
        Text('Counter: ${state.counter}'),
        Text('Description: ${state.description}'),
        ElevatedButton(
          onPressed: () => dispatch(IncrementAction()),
          child: Text('Increment'),
        ),
      ],
    );
  },
)

Using a Custom Model

For structured data, use a Tuple or custom class:

ReduxSelector<AppState, Tuple2<int, String>>(
  selector: (context, state) => Tuple2(state.counter, state.description),
  builder: (context, store, state, dispatch, model, child) {
    return Column(
      children: [
        Text('Counter: ${model.item1}'),
        Text('Description: ${model.item2}'),
        ElevatedButton(
          onPressed: () => dispatch(IncrementAction()),
          child: Text('Increment'),
        ),
      ],
    );
  },
)

Choosing Between StoreConnector and ReduxSelector

Both approaches manage widget rebuilds during state changes, but serve different use cases:

Use StoreConnector When:

  • You want to separate smart (store-aware) and dumb (presentational) widgets
  • You need view-models with explicit equality comparison
  • You're building reusable UI components that shouldn't know about Redux
  • You want to test UI widgets in isolation without a store
class MyCounterConnector extends StatelessWidget {
  Widget build(BuildContext context) {
    return StoreConnector<AppState, ViewModel>(
      vm: () => Factory(this),
      builder: (context, vm) => MyCounter(
        counter: vm.counter,
        description: vm.description,
        onIncrement: vm.onIncrement,
      ),
    );
  }
}

class ViewModel extends Vm {
  final int counter;
  final String description;
  final VoidCallback onIncrement;

  ViewModel({
    required this.counter,
    required this.description,
    required this.onIncrement,
  }) : super(equals: [counter, description]);
}

Use ReduxSelector When:

  • You prefer minimal boilerplate
  • Direct store access within a single widget is acceptable
  • You want Provider-style dependency injection
  • You're integrating with existing Provider-based code
ReduxSelector<AppState, dynamic>(
  selector: (context, state) => [state.counter, state.description],
  builder: (context, store, state, dispatch, model, child) {
    return MyCounter(
      counter: state.counter,
      description: state.description,
      onIncrement: () => dispatch(IncrementAction()),
    );
  },
)

Migration Strategy

Both Provider and AsyncRedux connectors work simultaneously, enabling gradual migration:

// Old code using StoreConnector continues to work
class OldFeatureConnector extends StatelessWidget {
  Widget build(BuildContext context) {
    return StoreConnector<AppState, OldViewModel>(
      vm: () => OldFactory(this),
      builder: (context, vm) => OldFeatureWidget(vm: vm),
    );
  }
}

// New code can use ReduxSelector
class NewFeatureWidget extends StatelessWidget {
  Widget build(BuildContext context) {
    return ReduxSelector<AppState, dynamic>(
      selector: (context, state) => [state.newFeature],
      builder: (context, store, state, dispatch, model, child) {
        return NewFeatureContent(feature: state.newFeature);
      },
    );
  }
}

This allows you to migrate incrementally without rewriting your entire application.

Comparison Summary

AspectStoreConnectorReduxSelector
BoilerplateMore (ViewModel + Factory)Less (inline selector)
SeparationSmart/Dumb widget patternSingle widget
TestingEasy to test UI in isolationRequires store setup
Provider compatibilityNative AsyncReduxFull Provider integration
Rebuild controlVia ViewModel equalityVia selector list

References

URLs from the documentation: