Redux Compact is a library that aims to reduce the massive amount of boilerplate that follows maintaining a Flutter Redux application.

Overview

Redux Compact

Redux Compact is a library that aims to reduce the massive amount of boilerplate that follows maintaining a Flutter Redux application.

The library provides a set of middleware and a reducer that intercepts a special kind of action called Compact Action. The action has direct access to the state and can be both sync- and asynchronous and provides you the ability to chain actions. The action’s reducer is a method called reduce which allows you to make corresponding state changes within the action itself.

This approach eliminates the need to maintain separate files and folders for actions and reducers and to create and dispatch multiple actions to handle asynchronous state.

Usage

This documentation assumes that you are already familiar with Redux and Flutter Redux, their core concepts, setup and usage.

For a full overview visit the examples

Create your store as recommended by Flutter Redux. Add Redux Compact middleware and reducer to the store.

final compactReducer = ReduxCompact.createReducer<AppState>();
final compactMiddleware = ReduxCompact.createMiddleware<AppState>();

final store = new Store<AppState>(
  compactReducer, // <-- Add compactReducer
  initialState: AppState.initialState(),
  middleware: [
    compactMiddleware, // <-- Add compactMiddleware
  ],
);

Then dispatch an action that extends CompactAction

class IncrementCountAction extends CompactAction<AppState> {
  final int incrementBy;

  IncrementCountAction(this.incrementBy);

  @override
  AppState reduce() {
    return state.copy(
      counter: state.counter + incrementBy
    );
  }
}

Global error handling

You can add a global error handler to all your asynchrounus actions simply by implementing the onError function when creating the middleware. The function accepts dynamic error and the dispatch function as parameters.

  ReduxCompact.createMiddleware<AppState>(
    onError: (error, dispatch) => yourErrorFunction(error, dispatch)
  );

Compact Action

In order to use Redux Compact you must dispatch an action that extends a CompactAction.

All compact actions must implement the reduce method which is the reducer for the action. The reduce method has direct access to instance variables, dispatch function and the store state.

Keep in mind

  • Like normal reducers the reduce method always expects to return a state. If you do not wish to update the state, simply return state (returning null updates the state to null).
  • Even though the reduce method has access to the dispatch function, dispatching an action in a reducer is an anti-pattern. If you wish to dispatch another action read the chaining actions section.

Sync action

class IncrementCountAction extends CompactAction<AppState> {
  final int incrementBy;

  IncrementCountAction(this.incrementBy);

  @override
  AppState reduce() {
    return state.copy(
      counter: state.counter + incrementBy,
    );
  }
}

Async Action

To create an asynchronous action you simply need to implement the makeRequest() method as a Future. As your request executes the values of request instance variable change allowing you to make state changes accordingly.

The request object contains:

  • loading: true if a request is in flight, false otherwise
  • error: dynamic if an error occurs, null otherwise
  • data: dynamic if the request is successful, null otherwise
class IncrementCountAction extends CompactAction<AppState> {
  final int incrementBy;

  IncrementCountAction(this.incrementBy);

  @override
  makeRequest() {
    // The makeRequest() method has direct access to
    // instance variable and current state
    const count = state.counter + incrementBy;
    final url = "http://numbersapi.com/$count";

    // Return a future
    return http.read(url);
  }

  @override
  AppState reduce() {
    // If we are waiting for a response loading, will be true.
    if (request.loading) {
      return state.copy(isLoading: request.loading);
    }

    // hasError is a helper function that checks if error != null
    if (request.hasError) {
      return state.copy(
        errorMsg: error.message,
      );
    }

    // The request was successful
    return state.copy(
      counter: state.counter + 1,
      description: request.data,
    );
  }
}

Chaining Actions

Compact Action provides two helper functions: before and after. Both of these methods have direct access to the state, dispatch function and class instance variables. You can therefore call or dispatch, other functions or actions, before or after the current action runs.

  • The before method always runs before the reduce method and asynchronous requests.

  • The after method runs after the reduce method, or when an asynchronous request has finished successfully. If an error occurred in an asynchronous request the method will not run.

Just remember the state:

  • Has not changed in the before method
  • Has changed in the after method
class IncrementCountAction extends CompactAction<AppState> {
  final int incrementBy;

  IncrementCountAction(this.incrementBy);

  @override
  AppState reduce(RequestStatus status) {
    // The reducer only increments the count
    return state.copy(
      counter: state.counter + incrementBy,
    );
  }

  @override
  void before() {
    // Before the reducer runs we dispatch an action
    // that copies the current state.
    dispatch(SetPreviousDescAction());
  }

  @override
  void after() {
    // After the reduce method runs
    // We dispatch an action to fetch a description for the counter
    dispatch(FetchDescriptionAction(state.counter));
  }
}

BaseModel

BaseModel is a convenient class to quickly create a ViewModel for the Redux StoreConnector. It has direct access to the store state and the dispatch function. You can therefore dispatch an action within the model or the widget.

BaseModel is not a mandatory class for Redux Compact. You can use basic ViewModels if you want as long as you dispatch a CompactAction. If you would like to use a BaseModel, create a class that extends BaseModel and implement the fromStore method.

class _VM extends BaseModel<AppState> {
  final int count;

  _VM(Store store, { this.count }) : super(store);

  @override
  AppState fromStore() {
    return _VM(store, count: state.counter);
  }

  // You can dispatch an action from the VM
  // or call vm.dispatch(...) from the widget
  void incrementCount() {
    dispatch(IncrementCountAction(state.counter + 1));
  }
}

Then initialize BaseModel with the fromStore method in the in the Widget's StoreConnector

class CounterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StoreConnector<AppState, _VM>(
      converter: (store) => _VM(store).fromStore(), // <-- Initialize the VM
      builder: (context, vm) => Container(...),
    );
  }
You might also like...

Flutter library that handles BLE operations for multiple devices

Flutter reactive BLE library Flutter library that handles BLE operations for multiple devices. Usage The reactive BLE lib supports the following: BLE

Apr 12, 2022

A Dart library to parse Portable Executable (PE) format

pefile A Dart library to parse Portable Executable (PE) format Usage A simple usage example: var pe = pefile.parse('C:\\Windows\\System32\\notepad.exe

Sep 12, 2022

This library contains methods that make it easy to consume Mpesa Api.

This library contains methods that make it easy to consume Mpesa Api. It's multi-platform, and supports CLI, server, mobile, desktop, and the browser.

Dec 15, 2021

An alternative random library for Dart.

Randt Randt library for Dart... Description Use Randt to get a random integer from a list, generate random integer in a specific range and generate ra

Nov 21, 2021

A library for YAML manipulation with comment and whitespace preservation.

Yaml Editor A library for YAML manipulation while preserving comments. Usage A simple usage example: import 'package:yaml_edit/yaml_edit.dart'; void

Dec 26, 2022

A comprehensive, cross-platform path manipulation library for Dart.

A comprehensive, cross-platform path manipulation library for Dart. The path package provides common operations for manipulating paths: joining, split

Dec 29, 2022

A fast algorithm for finding polygon pole of inaccessibility implemented as a Dart library.

polylabel Dart port of https://github.com/mapbox/polylabel. A fast algorithm for finding polygon pole of inaccessibility implemented as a Dart library

Nov 13, 2021

Dart library for unescaping HTML-encoded strings

html_unescape A Dart library for unescaping HTML-encoded strings. Supports: Named Character References ( ) 2099 of them Decimal Character Referen

Dec 20, 2022

The `TypedEventNotifier` library allows notifying listeners with an object.

The TypedEventNotifier library allows notifying listeners with an object. listeners can be subscribed to only a special type or group of objects.

Nov 13, 2021
Comments
  • Clearing errors in State

    Clearing errors in State

    Context:

    • When handling errors, we update the error in State to show a snack bar then we must clear the error in State
    • Almost time we must clear the error in State after setting the error in the State but we can do that in reducer and after is not called when the makeRequest is failed as well

    So what is a good way to clear errors in State

    opened by phamnhuvu-dev 0
Owner
Ómar Óskarsson
Ómar Óskarsson
Boilerplate-free form validation library

Valform Boilerplate-free form validation library. Preface Why? Why not Formz? Why Valform? Getting started Simple Usage Inspiration Why? There is no c

Alexander Farkas 3 Nov 14, 2021
Boilerplate-free form validation library

Trigger Boilerplate-free form validation library. Preface Why? Why not Formz? Why Trigger? Getting started Simple Usage Inspiration Why? There is no c

Alexander Farkas 3 Nov 14, 2021
This project aims to basically listing crypto market prices and set alarms.

trader This project aims to basically listing crypto market prices and set alarms. Also, it is starting point of Flutter with GetX state management. B

Görkem Sarı 2 Oct 31, 2021
Starter project and code generator for Flutter/Redux

Flutter Redux Starter/Code Generator Videos Short video ~ 1 minute Long video ~ 10 minutes We're using this approach to develop the Flutter app for In

Hillel Coren 278 Dec 12, 2022
Fluro is a Flutter routing library that adds flexible routing options like wildcards, named parameters and clear route definitions.

Fluro is a Flutter routing library that adds flexible routing options like wildcards, named parameters and clear route definitions.

Luke Pighetti 3.5k Jan 4, 2023
Scribble is a lightweight library for freehand drawing in Flutter supporting pressure, variable line width and more!

Scribble Scribble is a lightweight library for freehand drawing in Flutter supporting pressure, variable line width and more! A

Tim Created It. 73 Dec 16, 2022
The Dart Time Machine is a date and time library for Flutter, Web, and Server with support for timezones, calendars, cultures, formatting and parsing.

The Dart Time Machine is a date and time library for Flutter, Web, and Server with support for timezones, calendars, cultures, formatting and parsing.

null 2 Oct 8, 2021
A Flutter library to make Rest API clients more easily. Inspired by Java Feing.

A Flutter library to make Rest API clients more easily. Inspired by Java Feing. Features Facilitated JSON encode and decode using common interfaces. F

null 2 Mar 15, 2022
Flutter library to add gestures and animations to each Shape you draw on your canvas in your CustomPainter

Flutter library to bring your CustomPainter ?? to Life ✨ ⚡️ touchable library gives you the ability to add various gestures and animations to each Sha

Natesh Bhat 190 Jan 7, 2023
A Flutter plugin for XUpdate -- Android Update Library

flutter_xupdate A Flutter plugin for XUpdate -- Android Update Library。See the use Chinese Document for details。 About me WeChat public number juejin

薛翔 233 Dec 25, 2022