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. NonotifyListeners()orsetState()required. - 🧬 Lifecycle-Aware: States are bound to the lifecycle of ViewModels or Widgets, ensuring zero memory leaks through automatic resource cleanup.
- 🏗️ Structured State: Provides
RStatefor mutable values andComputedStatefor derived data with automatic dependency tracking. - 🔄 Compose-like DX: Use
rememberMutableStateto persist reactive state across widget rebuilds, offering a developer experience similar to Jetpack Compose. - 🛠️ Bridge Utilities: Easily convert legacy
ValueNotifierorChangeNotifierinto 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 onObject,List,Set,Map, andValueNotifierto convert values directly intoRStateComputer(e.g."Guest".asStateOf,[1, 2].asStateOf,notifier.asStateOf). Preferred over functional initializers..asNullableStateOf: Extension getter onObject,List,Set,Map, andValueNotifierfor nullable value initializers (e.g."Guest".asNullableStateOf,map.asNullableStateOf,notifier.asNullableStateOf).nullAsStateOf<T>(): Helper initializer for creating anullvalueRStateComputer<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)(ornotifier.asStateOf): Converts aValueNotifierinto a reactive computer.stateOfChangeNotifier(changeNotifier: notifier, computer: (cn) => cn.value): Converts anyChangeNotifierinto a reactive computer.stateOfAsync({required T initialValue, Future<T>? future, Stream<T>? stream, ...}): Converts aFutureorStreaminto a reactive computer. ReturnsinitialValueuntil an async value is received. Supports lazy factoriesfFactory/fFactory2(cancellable)andsFactory/sFactory2(cancellable).stateOfAsyncData<T>({T? initialValue, Future<T>? future, Stream<T>? stream, ...}): Converts aFutureorStreaminto a reactiveAsyncData<T>computer (starts asAsyncData.loading()orAsyncData.value(initialValue)). Supports lazy factoriesfFactory/fFactory2(cancellable)andsFactory/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 toAsyncData.loading().toData(T data): Sets state toAsyncData.data(data).toError(Object error, [StackTrace? st]): Sets state toAsyncData.error(error, st).toDataLoading(): Keeps existing data ifhasDatais true and setsAsyncData.dataLoading(data), otherwise setsAsyncData.loading().toDataLoadingRaw(T data): Sets state toAsyncData.dataLoading(data).toDataError(Object error, [StackTrace? st]): Keeps existing data ifhasDatais true and setsAsyncData.dataError(data, error, st), otherwise setsAsyncData.error(error, st).toDataErrorRaw(T data, Object error, [StackTrace? st]): Sets state toAsyncData.dataError(data, error, st).
Refreshable & Paginated States
-
RefreshableState<T>: ExtendsRState<AsyncData<T>>for managing refreshable async data.- Constructor accepts
autoLoad(true: triggersreloadData(),false: triggersrefreshData(),null: disables automatic loading; defaults totrue). refreshData({Cancellable? cancellable}): Clears state toloadingand reloads data.reloadData({Cancellable? cancellable}): Keeps previous data (dataLoading) while reloading.
- Constructor accepts
-
RefreshablePagerState<T, K, Pager>: ExtendsRefreshableState<List<T>>for managing paginated data using an_pager.loadNextPage({Cancellable? cancellable}): Fetches the next page using the last page'snextPageKeyand 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
stateRefreshableOfandstateRefreshablePagerOfin 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.rememberRefreshableStateandcontext.rememberRefreshablePagerStatein 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: