an_state 1.4.0
an_state: ^1.4.0 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. 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.0
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.refreshData({Cancellable? cancellable}): Clears state toloadingand reloads data.reloadData({Cancellable? cancellable}): Keeps previous data (dataLoading) while reloading.
-
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>).
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() and reloadData(). |
RefreshablePagerState |
Class |
Reactive state class for paginated refreshable data with loadNextPage(), refreshData(), and reloadData(). |
Issues #
If you encounter issues, here are some tips for debug, if nothing helps report to issue tracker on GitHub: