Skip to main content

an_state 1.4.2 copy "an_state: ^1.4.2" to clipboard
an_state: ^1.4.2 copied to clipboard

A reactive state management library for Flutter, providing seamless integration between ViewModels, Widgets, and reactive observables.

an_state #

an_state is a powerful, lightweight reactive state management library for Flutter. It seamlessly integrates the high-performance reactive engine of an_reactive_state, the robust lifecycle management of an_viewmodel, and the elegant state persistence of remember.

Important

an_state strongly depends on anlifecycle. All core features, including rememberState, rememberMutableState, and context.viewModels(), require a valid Lifecycle context provided within the widget tree.


🚀 Key Features #

  • 🎯 Transparent Reactivity: Based on an_reactive_state, UI updates automatically when state changes. No notifyListeners() or setState() required.
  • 🧬 Lifecycle-Aware: States are bound to the lifecycle of ViewModels or Widgets, ensuring zero memory leaks through automatic resource cleanup.
  • 🏗️ Structured State: Provides RState for mutable values and ComputedState for derived data with automatic dependency tracking.
  • 🔄 Compose-like DX: Use rememberMutableState to persist reactive state across widget rebuilds, offering a developer experience similar to Jetpack Compose.
  • 🛠️ Bridge Utilities: Easily convert legacy ValueNotifier or ChangeNotifier into modern reactive sources.

📦 Getting Started #

Installation #

Add the dependency to your pubspec.yaml:

dependencies:
  an_state: ^1.4.2

Mandatory Lifecycle Setup #

Initialize the lifecycle system at the root of your application:

import 'package:anlifecycle/anlifecycle.dart';

void main() {
  runApp(
    LifecycleApp( // 1. Wrap with LifecycleApp
      child: MaterialApp(
        // 2. Add the navigator observer
        navigatorObservers: [LifecycleNavigatorObserver.hookMode()],
        home: const HomePage(),
      ),
    ),
  );
}

📖 Usage Guide #

1. Local Widget State #

For UI-only state (like a toggle or a counter), use remember extensions to avoid boilerplate StatefulWidgets.

@override
Widget build(BuildContext context) {
  // Persists across rebuilds, disposed when the widget is removed from the tree
  // Requires Lifecycle context
  final isExpanded = context.rememberMutableState(false.asStateOf);

  return Column(
    children: [
      Text("Details are ${isExpanded.value ? 'Visible' : 'Hidden'}"),
      ElevatedButton(
        onPressed: () => isExpanded.value = !isExpanded.value,
        child: const Text("Toggle"),
      ),
    ],
  );
}

2. In ViewModels (Business Logic) #

Define your states using stateMutableOf and stateOf. These states will be automatically disposed of when the ViewModel is cleared.

class UserViewModel extends ViewModel {
  // Use .asStateOf extension to initialize mutable state
  late final username = stateMutableOf("Guest".asStateOf);

  // Computed state depends on username
  late final greeting = stateOf(() => "Hello, ${username.value}!");

  void updateName(String newName) {
    username.value = newName; // UI updates automatically
  }
}

3. In Widgets (UI Layer) #

Access ViewModels and observe states with minimal boilerplate.

@override
Widget build(BuildContext context) {
  // Fetch ViewModel via extension (requires Lifecycle context)
  final vm = context.viewModels<UserViewModel>(factory: UserViewModel.new);

  // Use listenReactiveState to subscribe to a single state and get its value
  final name = context.listenReactiveState(vm.username);
  final message = context.listenReactiveState(vm.greeting);

  // Or use listenReactiveStates to observe multiple reactive states at once.
  // Executes in a reactive scope (`effect`), automatically tracking accessed state dependencies.
  context.listenReactiveStates(() {
    print("Active User: ${vm.username.value}");
  });

  // Consuming AsyncData states with AsyncDataStateExt
  final userState = vm.userState; // RState<AsyncData<User>>
  context.listenReactiveState(userState);

  if (userState.isLoading) {
    return const CircularProgressIndicator();
  } else if (userState.isError) {
    return Text("Error: ${userState.error}");
  }

  return Column(
    children: [
      Text("User: ${userState.data.name}, Message: $message"),
      TextField(onChanged: vm.updateName),
    ],
  );
}

🛠️ Advanced Tools #

Initializers & Extension Getters #

  • .asStateOf: Extension getter on Object, List, Set, Map, and ValueNotifier to convert values directly into RStateComputer (e.g. "Guest".asStateOf, [1, 2].asStateOf, notifier.asStateOf). Preferred over functional initializers.
  • .asNullableStateOf: Extension getter on Object, List, Set, Map, and ValueNotifier for nullable value initializers (e.g. "Guest".asNullableStateOf, map.asNullableStateOf, notifier.asNullableStateOf).
  • nullAsStateOf<T>(): Helper initializer for creating a null value RStateComputer<T?> (e.g. nullAsStateOf<User>()).
  • stateValueOf(T value): Functional initializer for a simple value.
  • stateListOf(List<T> list): Functional initializer for a reactive list.
  • stateMapOf(Map<K, V> map): Functional initializer for a reactive map.
  • stateSetOf(Set<E> set): Functional initializer for a reactive set.

Bridge Tools #

  • stateOfValueNotifier(notifier) (or notifier.asStateOf): Converts a ValueNotifier into a reactive computer.
  • stateOfChangeNotifier(changeNotifier: notifier, computer: (cn) => cn.value): Converts any ChangeNotifier into a reactive computer.
  • stateOfAsync({required T initialValue, Future<T>? future, Stream<T>? stream, ...}): Converts a Future or Stream into a reactive computer. Returns initialValue until an async value is received. Supports lazy factories fFactory/fFactory2(cancellable) and sFactory/ sFactory2(cancellable).
  • stateOfAsyncData<T>({T? initialValue, Future<T>? future, Stream<T>? stream, ...}): Converts a Future or Stream into a reactive AsyncData<T> computer (starts as AsyncData.loading() or AsyncData.value(initialValue)). Supports lazy factories fFactory/fFactory2(cancellable) and sFactory/sFactory2(cancellable).

AsyncDataStateExt Extensions #

Convenient extensions on RState<AsyncData<T>>:

  • State Checkers: isLoading, isError, isData, hasData, data, dataOrNull, error, stackTrace.
  • State Mutators:
    • toLoading(): Sets state to AsyncData.loading().
    • toData(T data): Sets state to AsyncData.data(data).
    • toError(Object error, [StackTrace? st]): Sets state to AsyncData.error(error, st).
    • toDataLoading(): Keeps existing data if hasData is true and sets AsyncData.dataLoading(data), otherwise sets AsyncData.loading().
    • toDataLoadingRaw(T data): Sets state to AsyncData.dataLoading(data).
    • toDataError(Object error, [StackTrace? st]): Keeps existing data if hasData is true and sets AsyncData.dataError(data, error, st), otherwise sets AsyncData.error(error, st).
    • toDataErrorRaw(T data, Object error, [StackTrace? st]): Sets state to AsyncData.dataError(data, error, st).

Refreshable & Paginated States #

  • RefreshableState<T>: Extends RState<AsyncData<T>> for managing refreshable async data.

    • Constructor accepts autoLoad (true: triggers reloadData(), false: triggers refreshData(), null: disables automatic loading; defaults to true).
    • refreshData({Cancellable? cancellable}): Clears state to loading and reloads data.
    • reloadData({Cancellable? cancellable}): Keeps previous data (dataLoading) while reloading.
  • RefreshablePagerState<T, K, Pager>: Extends RefreshableState<List<T>> for managing paginated data using an_pager.

    • loadNextPage({Cancellable? cancellable}): Fetches the next page using the last page's nextPageKey and appends data.
    • refreshData({Cancellable? cancellable}): Clears pages and reloads the first page.
    • reloadData({Cancellable? cancellable}): Keeps previous data (dataLoading) while reloading the first page.
    • pages: Getter for all loaded page instances (List<Pager>).
  • ViewModel Extensions: Use stateRefreshableOf and stateRefreshablePagerOf in ViewModels.

    class FeedViewModel extends ViewModel {
      late final userState = stateRefreshableOf((c) => fetchUser(c), autoLoad: true);
      late final feedState = stateRefreshablePagerOf((c, pageKey) => fetchFeed(pageKey, c));
    }
    
  • BuildContext Extensions: Use context.rememberRefreshableState and context.rememberRefreshablePagerState in Widgets.

    final userState = context.rememberRefreshableState((c) => fetchUser(c));
    final feedState = context.rememberRefreshablePagerState((c, pageKey) => fetchFeed(pageKey, c));
    

Optimization #

  • expensiveComputation(Computer<T> computer): Ensures a heavy calculation or registration logic runs only once during the state's lifecycle.

📚 Ecosystem & Underlying Packages #

an_state combines the strengths of several core libraries. For deeper learning on specific features, advanced APIs, or lifecycle details, please refer to their official documentations directly:

  • anlifecycle: Complete lifecycle management system for Flutter applications, routes, and widgets.
  • an_viewmodel: ViewModel architecture component for business logic and lifecycle-aware state scoping.
  • remember: Jetpack Compose-like state persistence and widget memory management.
  • an_reactive_state: Transparent, high-performance reactive state engine with automatic dependency tracking.

📋 Core API Reference #

Method Source Description
asStateOf / asNullableStateOf Extension Extension getters on values ("Guest".asStateOf, list.asStateOf, notifier.asStateOf) to create RStateComputer. Preferred.
stateMutableOf(computer) ViewModel Creates a mutable RState bound to ViewModel.
stateOf(computer) ViewModel Creates a read-only ComputedState.
rememberMutableState(computer) BuildContext Remembers a mutable state in the widget tree.
rememberState(computer) BuildContext Remembers a computed state in the widget tree.
listenReactiveState(state) BuildContext Watches a single state and returns its value (triggers rebuild). Alias: listenRawState.
listenReactiveStates(computer) BuildContext Watches multiple states accessed inside the callback (triggers rebuild).
stateOfAsync(...) Utility Converts a Future or Stream into a reactive computer.
stateOfAsyncData(...) Utility Converts a Future or Stream into a reactive AsyncData<T> computer.
AsyncDataStateExt Extension Convenience methods on RState<AsyncData<T>> for checking and mutating async states (toData, toDataLoading, toDataError, etc.).
RefreshableState Class Reactive state class for refreshable async data with refreshData(), reloadData(), and autoLoad.
RefreshablePagerState Class Reactive state class for paginated refreshable data with loadNextPage(), refreshData(), reloadData(), and autoLoad.
rememberRefreshableState BuildContext Remembers a RefreshableState in the widget tree.
rememberRefreshablePagerState BuildContext Remembers a RefreshablePagerState in the widget tree.
stateRefreshableOf ViewModel Creates a RefreshableState bound to ViewModel.
stateRefreshablePagerOf ViewModel Creates a RefreshablePagerState bound to ViewModel.

Issues #

If you encounter issues, here are some tips for debug, if nothing helps report to issue tracker on GitHub:

1
likes
160
points
401
downloads

Documentation

API reference

Publisher

verified publisheraymtools.com

Weekly Downloads

A reactive state management library for Flutter, providing seamless integration between ViewModels, Widgets, and reactive observables.

Repository (GitHub)
View/report issues

License

Apache-2.0 (license)

Dependencies

an_async_data, an_lifecycle_cancellable, an_pager, an_reactive_state, an_viewmodel, anlifecycle, cancellable, flutter, remember

More

Packages that depend on an_state