### Setup AsyncRedux Store with Environment Source: https://asyncredux.com/flutter/miscellaneous/dependency-injection When creating your AsyncRedux store, pass an instance of your custom Environment class. This makes the dependencies available throughout the store's lifecycle. ```dart store = Store( initialState: ..., environment: Environment(), ); ``` -------------------------------- ### OptimisticSync Mixin Example in Dart Source: https://asyncredux.com/flutter/advanced-actions/optimistic-mixins A complete example demonstrating how to implement the OptimisticSync mixin for a 'ToggleLike' action. It shows how to define methods for applying optimistic values, getting values from state, sending data to the server, and handling server responses and errors. ```dart class ToggleLike extends AppAction with OptimisticSync { final String itemId; ToggleLike(this.itemId); // Different items can sync concurrently. Object? optimisticSyncKeyParams() => itemId; // Toggle the current state. bool valueToApply() => !state.items[itemId].liked; // Apply the optimistic value. AppState applyOptimisticValueToState(AppState state, bool isLiked) => state.copy(items: state.items.setLiked(itemId, isLiked)); // Read value to detect if follow-up is needed. bool getValueFromState(AppState state) => state.items[itemId].liked; // Send to server. Future sendValueToServer(Object? value) async => await api.setLiked(itemId, value); // Apply server response (optional). AppState? applyServerResponseToState(AppState state, Object serverResponse) => state.copy(items: state.items.setLiked(itemId, serverResponse as bool)); // Handle completion (optional). Future onFinish(Object? error) async { if (error != null) { // Reload from server on error. var reloaded = await api.getItem(itemId); return state.copy(items: state.items.update(itemId, reloaded)); } return null; } } ``` -------------------------------- ### Configure Advanced Store Setup with Observers and Error Handling in Dart Source: https://asyncredux.com/index Details advanced setup options for the AsyncRedux Store, including stateObserver, errorObserver, actionObserver, and globalWrapError. It demonstrates how to handle specific exceptions like PlatformException. ```dart var store = Store( stateObserver: [MyStateObserver()], errorObserver: [MyErrorObserver()], actionObservers: [MyActionObserver()], globalWrapError: MyGlobalWrapError(), ); ``` ```dart Object? wrap(error, stackTrace, action) => (error is PlatformException) ? UserException('Error connecting to Firebase') : error; } ``` -------------------------------- ### MyCounter Dumb Widget Example Source: https://asyncredux.com/flutter/connector/store-connector An example of a simple dumb widget, MyCounter, that displays a counter and a description, and provides a callback to increment the counter. This widget is designed to be used with a StoreConnector. ```dart MyCounter( counter: 2, description: "2 is the first non-zero even number", onIncrement: () { ... }, ); ``` -------------------------------- ### Save Todo Action Example (Dart) Source: https://asyncredux.com/flutter/advanced-actions/optimistic-mixins Demonstrates a basic `SaveTodo` action without optimistic updates, showing the sequence of saving and then reloading the todo list. ```dart class SaveTodo extends AppAction { final Todo newTodo; SaveTodo(this.newTodo); Future reduce() async { await saveTodo(newTodo); var reloadedList = await loadTodoList(); return state.copy(todoList: reloadedList); } } ``` -------------------------------- ### Instantiate Store with Observers for Logging (Swift) Source: https://asyncredux.com/flutter/miscellaneous/logging Demonstrates how to instantiate a Redux store in Swift, providing custom action and state observers for logging purposes. This setup allows for detailed tracking of actions and state changes within the application. ```swift var store = Store( initialState: state, actionObservers: [Log.printer(formatter: Log.verySimpleFormatter)], stateObservers: [StateLogger()] ); ``` -------------------------------- ### Action Naming Convention Example (Dart) Source: https://asyncredux.com/flutter/basics/action-simplification Illustrates a common naming convention where actions have an `Action` suffix. Both `Increment` and `IncrementAction` extend `AppAction`, showcasing flexibility in naming. ```dart // One possible name class Increment extends AppAction { ... } // Another possible name class IncrementAction extends AppAction { ... } ``` -------------------------------- ### Setup Navigator Key for AsyncRedux Navigation (Dart) Source: https://asyncredux.com/flutter/miscellaneous/navigation This snippet demonstrates how to set up a global navigator key and inject it into AsyncRedux's NavigateAction during app initialization. This is a prerequisite for using AsyncRedux for navigation. ```dart final navigatorKey = GlobalKey(); void main() async { NavigateAction.setNavigatorKey(navigatorKey); ... } ``` -------------------------------- ### CounterWidget: Direct Store Access Example Source: https://asyncredux.com/flutter/connector/connector-pattern An example of a `CounterWidget` that directly accesses the Redux store's state (`context.state.counter`, `context.state.description`) and dispatches an action (`context.dispatch(IncrementAction())`). This widget is 'smart' as it contains store-related logic. ```dart // Widget that uses context.state directly class CounterWidget extends StatelessWidget { Widget build(BuildContext context) { return Column( children: [ Text('Counter: ${context.state.counter}'), // Here! Text('Description: ${context.state.description}'), // Here! ElevatedButton( onPressed: () => context.dispatch(IncrementAction()), // Here! child: Text('Increment'), ) ] ); } } ``` -------------------------------- ### Simulate No Internet for All Actions (Dart) Source: https://asyncredux.com/flutter/advanced-actions/internet-mixins This example shows how to force internet connectivity simulation for all actions using `CheckInternet`, `AbortWhenNoInternet`, or `UnlimitedRetryCheckInternet` by setting the `forceInternetOnOffSimulation` property on the store. Setting it to `() => false` simulates no internet for all actions. ```dart store.forceInternetOnOffSimulation = () => false; // Simulates NO internet for all actions ``` -------------------------------- ### Testing Asynchronous Actions with StoreTester Source: https://asyncredux.com/flutter/testing/store-tester Example demonstrating how to test a sequence of asynchronous Redux actions using `StoreTester`. It shows how to dispatch an action, wait for multiple actions to complete using `waitAll`, and assert the state changes after each action. ```dart var storeTester = StoreTester(initialState: AppState.initialState()); expect(storeTester.state.counter, 0); expect(storeTester.state.description, isEmpty); storeTester.dispatch(IncrementAndGetDescriptionAction()); TestInfoList infos = await storeTester.waitAll([ IncrementAndGetDescriptionAction, BarrierAction, IncrementAction, BarrierAction, ]); // Modal barrier is turned on (first time BarrierAction is dispatched). expect(infos.get(BarrierAction, 1).state.waiting, true); // While the counter was incremented the barrier was on. expect(infos[IncrementAction].waiting, true); // Then the modal barrier is dismissed (second time BarrierAction is dispatched). expect(infos.get(BarrierAction, 2).state.waiting, false); // In the end, counter is incremented, description is created, and barrier is dismissed. var info = infos[IncrementAndGetDescriptionAction]; expect(info.state.waiting, false); expect(info.state.description, isNotEmpty); expect(info.state.counter, 1); ``` -------------------------------- ### Correct Async Reducer Implementations in Dart Source: https://asyncredux.com/flutter/basics/async-actions Provides examples of correctly implemented asynchronous reducers in Dart for AsyncRedux. These examples ensure that the `reduce` method either performs an `await` operation or returns a non-completed future, adhering to AsyncRedux's rules. ```dart // Works AppState? reduce() { return state; } // Works AppState? reduce() { someFunc(); return state; } // Works Future reduce() async { await someFuture(); return state; } // Works Future reduce() async { await microtask; return state; } // Works Future reduce() async { if (state.someBool) return await calculation(); return null; } ``` -------------------------------- ### Initialize AsyncRedux Store with Initial State Source: https://asyncredux.com/flutter/basics/store Initializes the `Store` instance with an initial state, typically provided by a static `initialState` method on the `AppState` class. This ensures the store has a defined starting point for the application's state. Requires the async_redux package and a defined `AppState` class with an `initialState` method. ```dart var store = Store( initialState: AppState.initialState(), ); ``` -------------------------------- ### ViewModel with Custom Equality (Dart) Source: https://asyncredux.com/flutter/connector/store-connector Illustrates how to implement custom equality logic for ViewModel fields by extending VmEquals. This example shows comparing 'description' by equality and 'myObj' based on the length of its 'info' property, overriding the default identity comparison. ```dart class ViewModel extends Vm { final String description; final MyObj myObj; ViewModel({ required this.description, required this.myObj, }) : super(equals: [description, myObj]); } class MyObj extends VmEquals { String info; bool operator ==(Object other) => info.length == other.info.length; int get hashCode => 0; } ``` -------------------------------- ### ReduxAction Precondition Check with before() (Dart) Source: https://asyncredux.com/flutter/advanced-actions/before-and-after-the-reducer An example of using the before() method to check for preconditions, such as internet connectivity. If the precondition fails (e.g., no internet), a UserException is thrown, preventing the reduce() method from executing. ```dart Future before() async { if (!await hasInternetConnection()) throw UserException('No internet connection'); } ``` -------------------------------- ### Apply Server Push Updates (Dart) Source: https://asyncredux.com/flutter/advanced-actions/optimistic-mixins Example of ServerPush mixin for applying updates received from the server. It links to the associated optimistic update action and handles revision tracking. ```dart class PushLikeUpdate extends AppAction with ServerPush { final String itemId; final bool liked; final int serverRev; PushLikeUpdate({ required this.itemId, required this.liked, required this.serverRev, }); // Link to the OptimisticSyncWithPush action type. Type associatedAction() => ToggleLike; // Same key params as the associated action. Object? optimisticSyncKeyParams() => itemId; // The revision from the server push. int serverRevision() => serverRev; // Read server revision from state for this key. int? getServerRevisionFromState(Object? key) => state.items[key as String].serverRevision; // Apply the push and save the server revision. AppState? applyServerPushToState(AppState state, Object? key, int serverRevision) => state.copy( items: state.items.update( key as String, (item) => item.copy(liked: liked, serverRevision: serverRevision), ), ); } ``` -------------------------------- ### Testing AsyncRedux StoreConnector Lifecycle Methods with ConnectorTester Source: https://asyncredux.com/flutter/testing/testing-oninit-ondispose This snippet demonstrates how to test the onInit and onDispose methods of a StoreConnector using the ConnectorTester utility provided by AsyncRedux. It shows how to instantiate a Store, get a ConnectorTester for a specific widget, run the lifecycle methods, and assert that the expected actions are dispatched. ```dart var store = Store(...); var connectorTester = store.getConnectorTester(MyScreen()); connectorTester.runOnInit(); var action = await store.waitAnyActionTypeFinishes([PollInformationAction]); expect(action.start, true); connectorTester.runOnDispose(); var action = await store.waitAnyActionTypeFinishes([PollInformationAction]); expect(action.start, false); ``` -------------------------------- ### Bloc/Cubit with AsyncRedux Mixins for Simplified Logic Source: https://asyncredux.com/flutter/comparisons/bloc This example shows how AsyncRedux mixins (`CheckInternet`, `NonReentrant`, `Retry`) can be applied to a Bloc/Cubit to simplify the implementation of features like connectivity checks, re-entrance prevention, and retries. It uses helper methods like `nonReentrant` and `hasInternet` provided by the mixins. ```dart class PricesCubit extends Cubit with CheckInternet, NonReentrant, Retry { final PricesRepository repository; PricesCubit(this.repository) : super(PricesInitial()); Future load() async { await nonReentrant('load', () async { if (!await hasInternet()) { emit(PricesError('No internet connection')); return; } emit(PricesLoading()); try { final prices = await retryWithBackoff( () => repository.fetchPrices(), ); emit(PricesLoaded(prices)); } catch (e) { emit(PricesError(e.toString())); } }); } } ``` -------------------------------- ### Check Action Completion Status (Dart) Source: https://asyncredux.com/flutter/advanced-actions/action-status Provides examples of checking if an action has completed using `action.status.isCompleted`, `action.status.isCompletedOk`, and `action.status.isCompletedFailed`. It demonstrates both direct access via the action object and retrieval from `dispatchAndWait`. ```dart var action = MyAction(); await store.dispatchAndWait(action); print(action.isCompletedOk); var status = await store.dispatchAndWait(MyAction()); print(status.isCompletedOk); ``` -------------------------------- ### AsyncRedux StoreConnector with onInit and onDispose Source: https://asyncredux.com/flutter/testing/testing-oninit-ondispose This snippet shows a basic StatelessWidget that uses StoreConnector. The onInit method dispatches an action to start polling when the widget is initialized, and onDispose dispatches an action to stop polling when the widget is disposed. This is a common pattern for managing background tasks tied to screen lifecycle. ```dart class MyScreen extends StatelessWidget { Widget build(BuildContext context) => StoreConnector( vm: () => _Factory(), onInit: _onInit, onDispose: _onDispose, builder: (context, vm) => MyWidget(...), ); void _onInit(Store store) { store.dispatch(PollInformationAction(true)); } void _onDispose(Store store) { store.dispatch(PollInformationAction(false)); } } ``` -------------------------------- ### MyAction with before() and after() (Dart) Source: https://asyncredux.com/flutter/advanced-actions/before-and-after-the-reducer An example of a MyAction that dispatches BarrierAction in its before() and after() methods. The before() method dispatches BarrierAction(true) to show the barrier, and the after() method dispatches BarrierAction(false) to hide it. The reduce() method fetches data asynchronously. ```dart class MyAction extends AppAction { Future reduce() async { String description = await read(Uri.http("numbersapi.com","${state.counter}")); return state.copy(description: description); } void before() => dispatch(BarrierAction(true)); void after() => dispatch(BarrierAction(false)); } ``` -------------------------------- ### Example Console Output for ModelObserver - Text Source: https://asyncredux.com/flutter/miscellaneous/observing-rebuilds Illustrates the typical console output generated by `DefaultModelObserver` when state changes occur. It shows the state change number, rebuild status, connector type, and the associated ViewModel. ```text Model D:1 R:1 = Rebuid:true, Connector:MyWidgetConnector, Model:MyViewModel{B}. Model D:2 R:2 = Rebuid:false, Connector:MyWidgetConnector, Model:MyViewModel{B}. Model D:3 R:3 = Rebuid:true, Connector:MyWidgetConnector, Model:MyViewModel{C}. ``` -------------------------------- ### ViewModel State vs. CurrentState Example - Dart Source: https://asyncredux.com/flutter/connector/advanced-view-model Demonstrates the difference between the initial state ('state') and the most recent state ('currentState()') within a ViewModel factory. This is particularly relevant when dealing with asynchronous operations or callbacks where the state might change between the ViewModel's creation and the callback's execution. ```dart class Factory extends VmFactory { ViewModel fromStore() => ViewModel( onIncrement: () { // Prints 1/1 print(state.counter + '/' + currentState().counter); dispatchSync(IncrementAction()); // Prints 1/2 print(state.counter + '/' + currentState().counter); } ); } ``` -------------------------------- ### Dispatching AsyncRedux Events via Actions Source: https://asyncredux.com/flutter/basics/events Illustrates how AsyncRedux Actions can create and dispatch new, unspent events by updating the state. This includes examples for both boolean events and events carrying a String payload, demonstrating how to place them in the state. ```dart // Boolean event. class ClearText extends AppAction { AppState reduce() => state.copy(clearTextEvt: Evt()); // Here! } // Event with a String payload. class ChangeText extends AppAction { Future reduce() async { String newText = await fetchTextFromApi(); return state.copy(changeTextEvt: Evt(newText)); // Here! } } ``` -------------------------------- ### BuildContext Extensions for AsyncRedux State Access (Dart) Source: https://asyncredux.com/flutter/basics/using-the-store-state Provides extension methods on `BuildContext` to easily access the application's state (`AppState`). It includes methods for getting the full state, reading the state without rebuilding, and selecting specific parts of the state. Ensure `AppState` is replaced with your actual state class name if different. ```dart extension BuildContextExtension on BuildContext { AppState get state => getState(); AppState read() => getRead(); R select(R Function(AppState state) selector) => getSelect(selector); R? event(Evt Function(AppState state) selector) => getEvent(selector); } ``` -------------------------------- ### ViewModel Factory with Helper Methods (Dart) Source: https://asyncredux.com/flutter/connector/store-connector Demonstrates using helper methods within a VmFactory to construct parts of the ViewModel. This approach separates concerns, making the fromStore method cleaner and the ViewModel creation logic more modular, especially for complex ViewModels. ```dart class Factory extends VmFactory { Factory(connector) : super(connector); ViewModel fromStore() => ViewModel( counter: state.counter, description: _description(), onIncrement: _onIncrement, ); String _description() => state.description; void _onIncrement() => dispatch(IncrementAndGetDescriptionAction()); } ``` -------------------------------- ### Define AppState with Initial State in Dart Source: https://asyncredux.com/flutter/basics/state Extends the `AppState` class to include a static `initialState` method. This method provides a convenient way to get the default or starting state of the application, initializing `name` to an empty string and `age` to 0. ```dart class AppState { final String name; final int age; AppState({required this.name, required this.age}); static AppState initialState() => AppState(name: "", age: 0); } ``` -------------------------------- ### Instantiate Store with MetricsObserver Source: https://asyncredux.com/flutter/miscellaneous/metrics Demonstrates how to initialize an AsyncRedux store with a custom MetricsObserver to collect state change metrics. This involves passing a list of state observers during store instantiation. ```dart var store = Store( initialState: state, stateObservers: [MetricsObserver()], ); ``` -------------------------------- ### Initialize MockStore with Mocks Source: https://asyncredux.com/flutter/testing/mocking Demonstrates the initialization of a MockStore with a map of action types to their corresponding mocks. This allows for predefined mocking of specific actions during testing. ```dart var store = MockStore( initialState: initialState, mocks: { MyAction1 : ... MyAction2 : ... ... }, ); ``` -------------------------------- ### Initialize StoreTester from Store Source: https://asyncredux.com/flutter/testing/store-tester Demonstrates how to create a StoreTester instance from an existing Redux store. This is useful when you already have a store set up and want to test its behavior with specific actions. ```dart var store = Store(initialState: AppState.initialState()); var storeTester = StoreTester.from(store); ``` -------------------------------- ### Initialize Store with Persistor Source: https://asyncredux.com/flutter/miscellaneous/persistence Demonstrates the recommended way to initialize an AsyncRedux store with a custom persistor. It handles reading initial state from disk, creating default state if none exists, and then creating the store. ```dart var persistor = MyPersistor(); var initialState = await persistor.readState(); if (initialState == null) { initialState = AppState.initialState(); await persistor.saveInitialState(initialState); } var store = Store( initialState: initialState, persistor: persistor, ); ``` -------------------------------- ### Implement Waiting with WaitAction in Actions (Dart) Source: https://asyncredux.com/flutter/miscellaneous/advanced-waiting This example shows how to use `WaitAction.add` in the `before` method and `WaitAction.remove` in the `after` method of an action to manage waiting states automatically. ```dart class LoadAction extends AppAction { Future reduce() async { var newText = await loadText(); return state.copy(text: newText); } void before() => dispatch(WaitAction.add(this)); // Here! void after() => dispatch(WaitAction.remove(this)); // Here! } ``` -------------------------------- ### Create View-Model from Store and Factory (Dart) Source: https://asyncredux.com/flutter/testing/testing-the-view-model Demonstrates how to create a view-model instance using Vm.createFrom, passing a store and a factory. This method is used for testing and can only be called once per factory instance. It returns the view-model for inspection or callback invocation. ```dart var store = Store(initialState: User("Mary")); var vm = Vm.createFrom(store, MyFactory()); // Checking a view-model property. expect(vm.user.name, "Mary"); // Calling a view-model callback // and waiting for the action to finish. vm.onChangeNameTo("Bill"); // Dispatch SetNameAction("Bill") await store.waitActionType(SetNameAction); expect(store.state.name, "Bill"); // Calling a view-model callback // and waiting for the state to change. vm.onChangeNameTo("Bill"); // Dispatch SetNameAction("Bill") await store.waitCondition((state) => state.name == "Bill"); expect(store.state.name, "Bill"); ``` -------------------------------- ### StoreTester Initialization Source: https://asyncredux.com/flutter/testing/store-tester Demonstrates how to initialize the StoreTester, either from an existing store or directly from the initial state. ```APIDOC ## StoreTester Initialization ### Description Initialize the `StoreTester` by providing either an existing `Store` instance or the initial state of your application. ### Method Constructor / Factory Method ### Endpoint N/A ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```dart // From an existing store var store = Store(initialState: AppState.initialState()); var storeTester = StoreTester.from(store); // Directly from initial state var storeTester = StoreTester(initialState: AppState.initialState()); ``` ### Response #### Success Response (200) N/A #### Response Example N/A ``` -------------------------------- ### Retrieve Action Errors (Dart) Source: https://asyncredux.com/flutter/advanced-actions/action-status Explains how to get the error associated with a failed action using `action.status.originalError` for the raw error and `action.status.wrappedError` for any error modified by `wrapError()`. ```dart var error = action.status.originalError; var error = action.status.wrappedError; ``` -------------------------------- ### Provide AsyncRedux Store with StoreProvider Source: https://asyncredux.com/flutter/basics/store Wraps the entire widget tree with `StoreProvider` to make the store accessible throughout the application. This requires importing the `async_redux` package and passing the initialized store instance to the `store` property. The `child` property should contain the root of your widget tree, typically `MaterialApp` or `CupertinoApp`. ```dart import 'package:async_redux/async_redux.dart'; ... Widget build(context) { return StoreProvider( store: store, child: MaterialApp( ... ), ); } ``` -------------------------------- ### Flutter Widget Controllers (TextField, ListView) Source: https://asyncredux.com/flutter/basics/events Examples of native Flutter widgets like TextField and ListView that use controllers to manage their state. These controllers can be used to interact with the widgets programmatically. ```dart /// TextField example TextEditingController controller = TextEditingController(); TextField(controller: controller); /// ListView example ScrollController scrollController = ScrollController(); ListView( controller: scrollController, children: [ // list items... ); ``` -------------------------------- ### Dispatch WaitAction to Add/Remove Flags (Dart) Source: https://asyncredux.com/flutter/miscellaneous/advanced-waiting Shows how to dispatch `WaitAction` to add or remove flags, indicating the start and end of waiting processes. These flags can be any immutable object. ```dart dispatch(WaitAction.add("my flag")); // To add a flag. dispatch(WaitAction.remove("my flag")); // To remove a flag. ``` -------------------------------- ### Initialize Store with ConsoleActionObserver Source: https://asyncredux.com/flutter/miscellaneous/metrics Shows how to conditionally initialize the AsyncRedux store with `ConsoleActionObserver` only in debug or development modes. This helps in logging actions during development without affecting release builds. ```dart var store = Store( actionObservers: kReleaseMode ? null : [ConsoleActionObserver()], ); ``` -------------------------------- ### Dart: SendMsg Action with Basic Reduce Source: https://asyncredux.com/flutter/advanced-actions/wrapping-the-reducer A Dart example of a SendMsg action that sends a message and updates its status to 'sent'. It defines the Msg type and uses an AppAction base class. ```dart class SendMsg extends AppAction { final Msg msg; SendMsg(this.msg); Future reduce() async { await service.sendMessage(msg); return state.setMsg(msg.id, msg.copy(status: 'sent')); } } ``` -------------------------------- ### Implement ViewItem Action with Direct State Access Source: https://asyncredux.com/flutter/advanced-actions/action-selectors An example of a Redux action that selects an item by its ID directly from the state. It demonstrates how to find an item and handle cases where the item is not found. ```dart class ViewItem extends AppAction { final int id; ViewItem(this.id); AppState reduce() { Item? item = state.items.firstWhereOrNull((item) => item.id == id); if (item == null) throw UserException('Item not found'); return state.copy(viewedItem: item); } } ``` -------------------------------- ### Create ViewModel Factory (Dart) Source: https://asyncredux.com/flutter/connector/store-connector Shows the creation of a factory object that extends VmFactory to instantiate a ViewModel from the AppState. The fromStore method is responsible for mapping state properties and dispatching actions to create the ViewModel. ```dart class Factory extends VmFactory { Factory(connector) : super(connector); ViewModel fromStore() => ViewModel( counter: state.counter, description: state.description, onIncrement: () => dispatch(IncrementAndGetDescriptionAction()), ); } ``` -------------------------------- ### Granular Waiting Flags with Indices (Dart) Source: https://asyncredux.com/flutter/miscellaneous/advanced-waiting An advanced example showing how to use granular flags, such as button indices, with `WaitAction` to manage individual waiting states for multiple elements on a screen. ```dart int index; void before() => dispatch(WaitAction.add(index)); void after() => dispatch(WaitAction.remove(index)); // In widget: if (wait.isWaiting(index)) { // Show progress indicator for this specific item } ``` -------------------------------- ### Loading and Error Indicators: Bloc/Cubit Manual Implementation Source: https://asyncredux.com/flutter/comparisons/bloc Illustrates the manual implementation of loading and error indicators in Bloc/Cubit. This requires adding `isLoading` and `error` fields to the state and managing their updates within Cubit methods. ```dart // Widget final state = context.watch().state; if (state.error != null) return Text('Error'); else if (state.isLoading) return CircularProgressIndicator(); else return Text('Counter: ${state.counter}'); // State (needs isLoading and error fields) class CounterState { final int counter; final bool isLoading; final String? error; CounterState({required this.counter, required this.isLoading, this.error}); } // Cubit (needs to set isLoading and error fields) class CounterCubit extends Cubit { CounterCubit() : super(CounterState(counter: 0, isLoading: false)); Future increment(int amount) async { emit(state.copy(isLoading: true, error: null)); try { // ... do async work emit(state.copy(counter: state.counter + amount, isLoading: false)); } catch (error) { emit(state.copy(isLoading: false, error: error.toString())); } } } ``` -------------------------------- ### Initialize StoreTester Directly Source: https://asyncredux.com/flutter/testing/store-tester Shows how to initialize a StoreTester directly with an initial state. This method is convenient for setting up a fresh testing environment without needing a pre-existing store object. ```dart var storeTester = StoreTester(initialState: AppState.initialState()); ``` -------------------------------- ### Dispatch UserExceptionAction (Dart) Source: https://asyncredux.com/flutter/advanced-actions/errors-thrown-by-actions Provides an example of dispatching `UserExceptionAction` to display a user-facing error message without necessarily stopping the action's flow. This is useful for informing the user about non-critical issues. ```dart dispatch(UserExceptionAction('Please enter a valid number')); ``` -------------------------------- ### Extend Persistor Class Source: https://asyncredux.com/flutter/miscellaneous/persistence Provides a template for extending the abstract `Persistor` class in AsyncRedux. This example includes placeholder methods for reading, deleting, and persisting state, which need to be implemented with specific logic for disk operations. ```dart class MyPersistor extends Persistor { Future readState() async { // TODO: Put here the code to read the state from disk. return null; } Future deleteState() async { // TODO: Put here the code to delete the state from disk. } Future persistDifference({ required AppState? lastPersistedState, required AppState newState, }) async { // TODO: Put here the code to save the state to disk. } Future saveInitialState(AppState state) => persistDifference(lastPersistedState: null, newState: state); Duration get throttle => const Duration(seconds: 2); } ``` -------------------------------- ### Optimistic Update with Server Push (Dart) Source: https://asyncredux.com/flutter/advanced-actions/optimistic-mixins Example of OptimisticSyncWithPush for handling user intent with optimistic UI updates and server-pushed changes. It tracks local and server revisions to manage conflicts. ```dart class ToggleLike extends AppAction with OptimisticSyncWithPush { final String itemId; ToggleLike(this.itemId); Object? optimisticSyncKeyParams() => itemId; bool valueToApply() => !state.items[itemId].liked; AppState applyOptimisticValueToState(AppState state, bool isLiked) => state.copy(items: state.items.setLiked(itemId, isLiked)); bool getValueFromState(AppState state) => state.items[itemId].liked; // IMPORTANT: Must read the server revision from state for this key. int? getServerRevisionFromState(Object? key) => state.items[key as String].serverRevision; AppState? applyServerResponseToState(AppState state, Object serverResponse) => state.copy(items: state.items.setLiked(itemId, serverResponse as bool)); Future sendValueToServer(Object? value) async { // Get local revision BEFORE any await. int localRev = localRevision(); var response = await api.setLiked(itemId, value, localRev: localRev); // Inform the server revision from the response. informServerRevision(response.serverRev); return response.liked; } } ``` -------------------------------- ### Navigate to a Named Route using AsyncRedux (Dart) Source: https://asyncredux.com/flutter/miscellaneous/navigation This example illustrates how to dispatch a NavigateAction to push a named route onto the navigation stack. It utilizes the `pushNamed` static method provided by AsyncRedux's NavigateAction class. ```dart dispatch(NavigateAction.pushNamed("myRoute")); ``` -------------------------------- ### Dart: SendMsg Action Using AbortIfStateChanged Mixin Source: https://asyncredux.com/flutter/advanced-actions/wrapping-the-reducer A Dart example demonstrating how to use the AbortIfStateChanged mixin with a SendMsg action. This simplifies the action class by abstracting the reducer wrapping logic for state change detection. ```dart class SendMsg extends AppAction with AbortIfStateChanged { final Msg msg; SendMsg(this.msg); Future reduce() async { await service.sendMessage(msg); return state.setMsg(msg.id, msg.copy(status: 'sent')); } } ``` -------------------------------- ### Accessing Full State with context.state (Dart) Source: https://asyncredux.com/flutter/basics/using-the-store-state Demonstrates how to access the entire application state using `context.state` within a widget's build method. Widgets using `context.state` will automatically rebuild when any part of the store state changes. ```dart Widget build(context) { return Text('User name is ' + context.state.user.name); } ``` -------------------------------- ### Dispatch a Single Action Source: https://asyncredux.com/flutter/basics/dispatching-actions The `dispatch()` method is the most common way to dispatch a single action. It returns immediately. For synchronous actions, state updates before returning. For asynchronous actions, it starts a process that updates the state eventually. ```dart dispatch(MyAction()); ``` -------------------------------- ### ViewModel with Automatic Equality (Dart) Source: https://asyncredux.com/flutter/connector/store-connector Demonstrates how to automatically generate the operator == method for a ViewModel by including its fields in the 'equals' parameter of the Vm constructor. This ensures efficient UI updates by correctly comparing view-model instances. ```dart ViewModel({ required this.field1, required this.field2, }) : super(equals: [field1, field2]); ``` -------------------------------- ### Instantiate Store with DefaultModelObserver - Dart Source: https://asyncredux.com/flutter/miscellaneous/observing-rebuilds Demonstrates how to create an AsyncRedux store instance and provide a `DefaultModelObserver` to monitor state changes and rebuilds. This observer prints information to the console. ```dart var store = Store( initialState: state, modelObserver: DefaultModelObserver(), ); ``` -------------------------------- ### Define ViewModel with Basic Fields (Dart) Source: https://asyncredux.com/flutter/connector/store-connector Defines a ViewModel class extending Vm, containing basic fields like counter, description, and a callback for onIncrement. It automatically implements equality checks for 'counter' and 'description' by passing them to the super constructor's 'equals' parameter. ```dart 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]); } ``` -------------------------------- ### MyAction Using Barrier Mixin (Dart) Source: https://asyncredux.com/flutter/advanced-actions/before-and-after-the-reducer Demonstrates how to use the Barrier mixin in a MyAction class. By adding 'with Barrier', the MyAction automatically inherits the before() and after() methods for managing a modal barrier, simplifying the action's implementation. ```dart class MyAction extends AppAction with Barrier { Future reduce() async { String description = await read(Uri.http("numbersapi.com","${state.counter}")); return state.copy(description: description); } } ``` -------------------------------- ### Dart: SendMsg Action with wrapReduce for Race Condition Source: https://asyncredux.com/flutter/advanced-actions/wrapping-the-reducer An example in Dart showing how to use the wrapReduce method in a SendMsg action to prevent state overwrites due to race conditions. It compares the message state before and after the reducer runs. ```dart class SendMsg extends AppAction { final Msg msg; SendMsg(this.msg); Reducer wrapReduce(Reducer reduce) => () async { // Get the message object before the reducer runs. var previousMsg = state.getMsgById(msg.id); AppState? newState = await reduce(); // Get the current message object, after the reducer runs. var currentMsg = state.getMsgById(msg.id); // Only update the state if the message object hasn't changed. return identical(previousMsg, currentMsg) ? newState : null; } Future reduce() async { await service.sendMessage(msg); return state.setMsg(msg.id, msg.copy(status: 'sent')); } } ``` -------------------------------- ### Save and Load Simple Objects with LocalPersist Source: https://asyncredux.com/flutter/miscellaneous/persistence Demonstrates how to use the LocalPersist class to save and load lists of simple objects (numbers, booleans, strings, lists, maps) to a file. It supports appending data, checking file length, existence, and deletion. Note: This feature is not supported on the web. ```dart import 'package:async_redux/local_persist.dart'; // Example of simple objects List simpleObjs = [ 'Goodbye', 'Life is what happens\nwhen you are busy making other plans.', [100, 200, {"name": "João"}], true, 42, ]; // Create a LocalPersist instance var persist = LocalPersist("myFile"); // Save the list to the file await persist.save(simpleObjs); // Load the list from the file List loadedObjs = await persist.load(); // Append more data List moreObjs = ['Lets', 'append', 'more']; await persist.save(simpleObjs, append: true); // File operations int length = await persist.length(); bool exists = await persist.exists(); await persist.delete(); ``` -------------------------------- ### Incorrect Async Reducer Implementations in Dart Source: https://asyncredux.com/flutter/basics/async-actions Illustrates incorrect ways to implement asynchronous reducers in Dart for AsyncRedux. These examples violate the rule of not returning completed futures, which can lead to misbehavior in the application's state management. ```dart // Fails Future reduce() async { return state; } // Fails Future reduce() async { someFunc(); return state; } // Fails Future reduce() async { if (state.someBool) return await calculation(); return state; } ``` -------------------------------- ### MyCounterConnector with StoreConnector Source: https://asyncredux.com/flutter/connector/store-connector Shows how to create a connector widget, MyCounterConnector, using AsyncRedux's StoreConnector. It defines the view-model factory and the builder function to create the MyCounter widget. ```dart class MyCounterConnector extends StatelessWidget { Widget build(BuildContext context) { return StoreConnector( vm: () => Factory(this), builder: (...) => MyCounter(...) ``` ```dart class MyCounterConnector extends StatelessWidget { Widget build(BuildContext context) { return StoreConnector( vm: () => Factory(this), builder: (BuildContext context, ViewModel vm) => MyCounter( counter: vm.counter, description: vm.description, onIncrement: vm.onIncrement, )); } } ``` -------------------------------- ### Wait Until Error and Get Last TestInfo Source: https://asyncredux.com/flutter/testing/store-tester Runs until an action throws an error matching the provided `error` or `processedError`. Returns the info after the condition is met. The `processedError` is the error after being wrapped by the action's `wrapError()` method. ```dart Future waitUntilErrorGetLast({Object error, Object processedError}) ``` -------------------------------- ### Basic Selector for Filtered User Names Source: https://asyncredux.com/flutter/miscellaneous/cached-selectors This selector filters a list of users to include only those whose names start with a specific letter. It takes the application state and a text parameter, returning a list of matching User objects. ```dart List selectUsersWithNamesStartingWith(AppState state, {String text}) => state.users.where((user)=>user.name.startsWith(text)).toList(); ```