redarx 0.6.0

  • README.md
  • CHANGELOG.md
  • Installing
  • Versions
  • 39

Redarx

Experimental Dart State Management humbly inspired by ngrx <= Redux <= Elm, André Stalz work & Parsley.

redarx-principles

Examples

Principles

Requests to Commands Mapping via CommanderConfig

final requestMap = new Map<RequestType, CommandBuilder>()
  ..[RequestType.ADD_TODO] = AddTodoCommand.constructor()
  ..[RequestType.ARCHIVE] = ArchiveCommand.constructor()
  ..[RequestType.UPDATE_TODO] = UpdateTodoCommand.constructor()
  ..[RequestType.CLEAR_ARCHIVES] = ClearArchivesCommand.constructor()
  ..[RequestType.TOGGLE_SHOW_COMPLETED] = ToggleShowArchivesCommand.constructor();

Initialization

final cfg = new CommanderConfig<RequestType>(requestMap);
final store = new Store<TodoModel>(() => new TodoModel.empty());
final dispatcher = new Dispatcher();

final cmder = new Commander(cfg, store, dispatcher.onRequest);

var app = new AppComponent(querySelector('#app') )
..model$ = store.data$
..dispatch = dispatcher.dispatch
..render();

Dispatching requests

RequestType are defined via an enum

enum RequestType {
  ADD_TODO,
  UPDATE_TODO,
  ARCHIVE,
  CLEAR_ARCHIVES,
  TOGGLE_SHOW_COMPLETED
}

Requests are defined by a type and an optional payload.

dispatch( new Request(
    RequestType.ADD_TODO, withData: new Todo(fldTodo.value))
    );

Commands

Requests are mapped to commands by Commander and passed to the store.update()

exec(Request a) {
    store.update(config[a.type](a.payload));
  }

The commands define a public exec method which receive the currentState and return the new one.

class AddTodoCommand extends Command<TodoModel> {
  Todo todo;

  AddTodoCommand(this.todo);

  @override
  TodoModel exec(TodoModel model) => model..items.add(todo);

  static CommandBuilder constructor() {
    return (Todo todo) => new AddTodoCommand(todo);
  }
}

Async Commands

Async commands allows async evaluation of the new state

Store

Basically a (stream<Command<Model>>) => stream<Model> transformer

Receives new commands, and executes those with the current state/Model

Use a CommandStreamReducer<S extends Command, T extends AbstractModel> to stream reduced states

The store manage a stream of immutable states instances.

Reversible Store

The reversible store keep a history list of all executed commands and allow cancelling.

it provide an access to currentState by reducing all the commands history.

State listening

The store exposes a stream of immutable states

Stream<TodoModel> _model$;

set model$(Stream<TodoModel> value) {
_model$ = value;
    
modelSub = _model$.listen((TodoModel model) {
      list.todos = model.todos;
      footer.numCompleted = model.numCompleted;
      footer.numRemaining = model.numRemaining;
      footer.showCompleted = model.showCompleted;
    });
  }

Experimental multi-channel dispatcher (0.6.0)

Async commands are maybe not the best way to connect a Firebase data-source.

The redarx-ng-firebase example shows a way to dispatch firebase queries via a new dispatcher method : query.

Queries are dispatched to a Firebase service, which update the base. The service handles firebase.database child and values events and dispatch update request via the dispatch() method.

Event$ » Request$ » Command$ » state$

The Application State is managed in a Store<T extends AbstractModel>.

State is updated by commands, and the store keep a list of executed commands.

State is evaluated by commands updates,

In reversible-store, cancellation is allowed by simply remove the last command from "history".

A Commander listen to a stream of Requests dispatched by a Dispatcher injected in the application components | controllers | PM | VM

Each Request is defined by an RequestType enum, and can contains data.

Requests are "converted" to commands by the Commander, based on the CommanderConfig.map definition

  • the dispatcher.dispatch function is injected in view || controller || PresentationModel || ViewModel

  • Request are categorized by types, types are defined in RequestType enum

  • the dispatcher stream Requests

  • the dispatcher requestStream is injected in Commander, the commander listen to it, transforms Request to Command and transfer to the store.apply( command ) method

  • each Request is tied to a command via a CommanderConfig which is injected in Commander

// instanciate commands form requests 
config[request.type](request.payload);
  • Commander need a CommanderConfig containing a Map<RequestType,CommandBuilder>
  • the store then execute commandHistory and push the new model value to a model stream

TODO

  • ~~fix the generic/command ( <T extends Model> mess)~~
  • ~~implements a Scan stream transformer » to allow only run the last commands & emit the last reduced state~~
  • ~~async commands~~
  • ~~test Angular integration~~
  • ~~test with Firebase~~
  • use values types cf built_value
  • time travel / history UI
  • typed Request ? BookRequest, UserRequest ...?
  • tests
  • external config file ?
  • ...

Doubts

  • use a EnumClass implementation rather than dart enum type
  • dispatcher : use a streamController.add rather than dispatch method ?
  • multiple store ? dispatcher ? commander ?
  • each component could set an Request stream and the commander could maybe listen to it

Goals

  • study Dart : streams, generics, annotations, asynchrony...
  • study Redux & ngrx, play with reducers & Request/Commands mapping...
  • and more studies, more experiments, more play...
  • define a solid architecture for my coming projects

Changelog

0.6.0

  • prototypal "multi-channels" dispatcher (temporary):

    • query() => QUERIE$ => Prototypal FirebaseService integration
    • dispatch() => REQUEST$ => Commander
  • strong mode with no implicit casts or dynamic

0.5.0

  • immutable model
  • refactoring
  • Angular Dart compatible

0.4.0

  • Async Commands

0.2.1

  • CommandConfig : overload operator[] » allow accessing RequestType associated Command via config[RequestType]
  • generated doc

0.2.0

  • remove Dispatcher injection from AppRoot & Commander
  • dart doc generation

0.0.1

  • Initial version :
    • synchronous commands mapped to Action defined by ActionTypeEnum,
    • ActionType enum definition,
    • basic Action Dispatcher,
    • Commander : listen to dispatched action and
    • Store with Commands reducer
    • basic mapping config
    • basic undo

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  redarx: "^0.6.0"

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter packages get

Alternatively, your editor might support pub get or packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:redarx/redarx.dart';
        
Version Uploaded Documentation Archive
0.6.0 Dec 21, 2016 Go to the documentation of redarx 0.6.0 Download redarx 0.6.0 archive
0.5.0+1 Dec 20, 2016 Go to the documentation of redarx 0.5.0+1 Download redarx 0.5.0+1 archive
0.5.0 Dec 20, 2016 Go to the documentation of redarx 0.5.0 Download redarx 0.5.0 archive

Analysis

We analyzed this package on Apr 23, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.0.0-dev.49.0
  • pana: 0.10.6

Scores

Popularity:
Describes how popular the package is relative to other packages. [more]
0 / 100
Health:
Code health derived from static analysis. [more]
86 / 100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
65 / 100
Overall score:
Weighted score of the above. [more]
39
Learn more about scoring.

Platforms

Detected platforms: Flutter, web, other

No platform restriction found in primary library package:redarx/redarx.dart.

Suggestions

  • Fix analysis and formatting issues.

    Analysis or formatting checks reported 2 errors 8 hints.

    Strong-mode analysis of lib/src/commands-reducer-transformer.dart failed with the following error:

    line: 9 col: 7
    Missing concrete implementations of 'StreamTransformer.cast' and 'StreamTransformer.retype'.

    Run dartfmt to format lib/redarx.dart.

    Similar analysis of the following files failed:

    • lib/src/commander-config.dart (hint)
    • lib/src/commands.dart (hint)
    • lib/src/dispatcher.dart (hint)
    • lib/src/model.dart (hint)
    • lib/src/request.dart (hint)
    • lib/src/reversible-store.dart (hint)
    • lib/src/store.dart (hint)
  • Package is pre-v1 release.

    While there is nothing inherently wrong with versions of 0.*.*, it usually means that the author is still experimenting with the general direction API.

  • Maintain an example.

    Create a short demo in the example/ directory to show how to use this package. Common file name patterns include: main.dart, example.dart or you could also use redarx.dart.

  • Use analysis_options.yaml.

    Rename old .analysis_options file to analysis_options.yaml.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=1.0.0 <2.0.0
meta >=1.0.4 <2.0.0 1.1.2
Dev dependencies
test >=0.12.0 <0.13.0