w_flux 2.9.5

  • README.md
  • CHANGELOG.md
  • Installing
  • Versions
  • 31

w_flux

Pub Build Status codecov.io documentation

A Dart app architecture library with uni-directional data flow inspired by RefluxJS and Facebook's Flux.


Overview

flux-diagram

w_flux implements a uni-directional data flow pattern comprised of Actions, Stores, and FluxComponents.

  • Actions initiate mutation of app data that resides in Stores.
  • Data mutations within Stores trigger re-rendering of app view (defined in FluxComponents).
  • FluxComponents dispatch Actions in response to user interaction.
  • and the cycle continues...

What's Included

Action

An Action is a command that can be dispatched (with an optional data payload) and listened to.

In w_flux, Actions are the sole driver of application state change. FluxComponents dispatch Actions in response to user interaction with the rendered view. Stores listen for these Action dispatches and mutate their internal data in response, taking the Action payload into account as appropriate.

import 'package:w_flux/w_flux.dart';

// define an action
final Action<String> displayString = new Action<String>();

// dispatch the action with a payload
displayString('somePayload');

// listen for action dispatches
displayString.listen(_displayAlert);

_displayAlert(String payload) {
  print(payload);
}

BONUS: Actions are await-able!

They return a Future that completes after all registered Action listeners complete. It's NOT generally recommended to use this feature within normal app code, but it is quite useful in unit test code.

Store

A Store is a repository and manager of app state. The base Store class provided by w_flux should be extended to fit the needs of your app and its data. App state may be spread across many independent stores depending on the complexity of the app and your desired app architecture.

By convention, a Store's internal data cannot be mutated directly. Instead, Store data is mutated internally in response to Action dispatches. Stores should otherwise be considered read-only, publicly exposing relevant data ONLY via getter methods. This limited data access ensures that the integrity of the uni-directional data flow is maintained.

A Store can be listened to to receive external notification of its data mutations. Whenever the data within a Store is mutated, the trigger method is used to notify any registered listeners that updated data is available. In w_flux, FluxComponents listen to Stores, typically triggering re-rendering of UI elements based on the updated Store data.

import 'package:w_flux/w_flux.dart';

class RandomColorStore extends Store {

  // Public data is only available via getter method
  String _backgroundColor = 'gray';
  String get backgroundColor => _backgroundColor;

  // Actions relevant to the store are passed in during instantiation
  RandomColorActions _actions;

  RandomColorStore(RandomColorActions this._actions) {
    // listen for relevant action dispatches
    _actions.changeBackgroundColor.listen(_changeBackgroundColor);
  }

  _changeBackgroundColor(_) {
    // action dispatches trigger internal data mutations
    _backgroundColor = '#' + (new Random().nextDouble() * 16777215).floor().toRadixString(16);

    // trigger to notify external listeners that new data is available
    trigger();
  }
}

BONUS: Stores can be initialized with a stream transformer to modify the standard behavior of the trigger stream. This can be useful for throttling UI rendering in response to high frequency Store mutations.

import 'package:rate_limit/rate_limit.dart';
import 'package:w_flux/w_flux.dart';

class ThrottledStore extends Store {
  ...

  ThrottledStore(this._actions) : super.withTransformer(new Throttler(const Duration(milliseconds: 30))) {
    ...
  }
}

BONUS: Stores provide an optional terse syntax for action -> data mutation -> trigger operations.

// verbose syntax
actions.incrementCounter.listen(_handleAction);

_handleAction(payload) {
    // perform data mutation
    counter += payload;
    trigger();
  }

// equivalent terse syntax
triggerOnAction(actions.incrementCounter, (payload) => counter += payload);

FluxComponent

FluxComponents define the (optional) user interface for a w_flux unit and are responsible for rendering app view based on 'Store' data as needed. FluxComponents listen to Stores and selectively re-render in response to their trigger dispatches. FluxComponents retrieve relevant app data from these Stores via the exposed getter methods, and as such, are internally stateless.

If user interaction with a FluxComponent is intended to mutate app state, this is accomplished by dispatching an Action (with optional data payload). FluxComponents DO NOT mutate app state within Stores directly.

FluxComponent is an extension of Component (as provided by react-dart) that reduces the amount of boilerplate needed to operate within the w_flux architecture. The base FluxComponent class provided by w_flux should be extended to fit the needs of your app.

By default, FluxComponents provide standard getters for the Actions and Store that they are initialized with. They also automatically subscribe to the provided Store and re-render in response to its triggers.

import 'package:react/react.dart' as react;
import 'package:w_flux/w_flux.dart';

var RandomColorComponent = react.registerComponent(() => new _RandomColorComponent());
class _RandomColorComponent extends FluxComponent<RandomColorActions, RandomColorStore> {
  render() {
    return react.div({
      // accesses the backgroundColor via the store's public getter
      'style': {'padding': '50px', 'backgroundColor': store.backgroundColor, 'color': 'white'}
    }, [
      'This module uses a flux pattern to change its background color.',
      react.button({
        'style': {'padding': '10px', 'margin': '10px'},
        // triggers a change of background color by dispatching an action on button click
        'onClick': actions.changeBackgroundColor
      }, 'Change Background Color')
    ]);
  }
}

BONUS: Optional overrides are available for more granular control of FluxComponent rendering.

If the FluxComponent's Store is actually a complex object containing multiple Stores (each trigger independently), the component's redrawOn list can be overridden to confine re-rendering to trigger dispatches that originate from specific sub-stores.

The FluxComponent's getStoreHandlers method can be used to register more fine grained Store trigger handling if necessary.

import 'package:react/react.dart' as react;
import 'package:w_flux/w_flux.dart';

class ComplexStore {
  ThisStore thisOne = new ThisStore();
  ThatStore thatOne = new ThatStore();
  OtherStore otherOne = new OtherStore();
}

var ComplexComponent = react.registerComponent(() => new _ComplexComponent());
class _ComplexComponent extends FluxComponent<ComplexActions, ComplexStore> {

  // re-render will automatically be initiated in response to triggers from these two stores
  // (e.g. no rendering will occur on store.otherOne triggers)
  redrawOn() => [store.thisOne, store.thatOne];

  // whenever store.otherOne triggers, the _handleOtherTrigger method will be executed
  // (no rendering is triggered)
  getStoreHandlers() => {store.otherOne: _handleOtherTrigger};

  _handleOtherTrigger(otherStore) {
    // decide whether to re-render based on some criteria
    if (otherStore.isReady) {
      // manually initiate re-render of this component
      redraw();
    }
  }

  render() {
    ...
  }
}

over_react FluxUiComponent

If you are using the over_react package to build UI components, they offer a strongly-typed version of the "flux component" pattern shown above.

https://github.com/workiva/over_react#flux-component-boilerplate


Examples

Simple examples of w_flux usage can be found in the example directory. The example README includes instructions for building / running them.


External Consumption

w_flux implements a uni-directional data flow within an isolated application or code module. If w_flux is used as the internal architecture of a library, this internal data flow should be considered when defining the external API.

  • External API methods intended to mutate internal state should dispatch Actions, just like any internal user interaction.
  • External API methods intended to query internal state should leverage the existing read-only Store getter methods.
  • External API streams intended to notify the consumer about internal state changes should be dispatched from the internal Stores, similar to their triggers.
  • Factory constructors for useful 'root' FluxComponents can be exposed publicly for use in external react-dart based rendering hierarchies. These react components can be internally initialized with the Actions and Stores needed for normal operation without inadvertently exposing them externally.

w_module is a Dart library that defines a standard code module API that can be used seamlessly with w_flux internals to satisfy the above recommendations (complete with examples).


Development

This project leverages the dart_dev package for most of its tooling needs, including static analysis, code formatting, running tests, collecting coverage, and serving examples. Check out the dart_dev readme for more information.

Changelog

2.1.0

Support for react-dart 0.9.x (which moves to ReactJS 0.14)

2.0.0

Check out the detailed release notes.

  • Store now uses a named constructor when specifying a transformer instead of an optional constructor parameter

1.1.0

Check out the detailed release notes.

  • Added batched redraws

1.0.1

Check out the detailed release notes.

  • Relaxed react dependency range to include 0.8.x

1.0.0

Check out the detailed release notes.

There are no breaking changes in this release. The bump to 1.0.0 occurred as this project was open-sourced.

  • Now using dart_dev for tooling
  • Documentation and examples have been updated
  • Reporting code coverage to Codecov.io

0.3.0

Check out the detailed release notes.

  • Actions are now awaitable
  • FluxComponent provides a default implementation of getStoreHandlers
  • FluxComponent adds redrawOn
  • triggerOnAction with async onAction functions now works properly
  • BREAKING CHANGE   Store no longer extends Stream
  • BREAKING CHANGE   FluxComponent's stores getter is now store

0.2.0

  • Shorter action dispatch
  • Add triggerOnAction to store
  • Support throttling of store triggers
  • Allow react-dart 0.7.x releases

0.1.0

  • Initial version of w_flux

Use this package as a library

1. Depend on it

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


dependencies:
  w_flux: ^2.9.5

2. Install it

You can install packages from the command line:

with pub:


$ pub get

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

3. Import it

Now in your Dart code, you can use:


import 'package:w_flux/w_flux.dart';
  
Version Uploaded Documentation Archive
2.9.5 Mar 8, 2018 Go to the documentation of w_flux 2.9.5 Download w_flux 2.9.5 archive
2.9.4 Oct 3, 2017 Go to the documentation of w_flux 2.9.4 Download w_flux 2.9.4 archive
2.9.3 Aug 25, 2017 Go to the documentation of w_flux 2.9.3 Download w_flux 2.9.3 archive
2.9.2 Aug 21, 2017 Go to the documentation of w_flux 2.9.2 Download w_flux 2.9.2 archive
2.9.1 Aug 15, 2017 Go to the documentation of w_flux 2.9.1 Download w_flux 2.9.1 archive
2.9.0 Aug 11, 2017 Go to the documentation of w_flux 2.9.0 Download w_flux 2.9.0 archive
2.8.0 Aug 10, 2017 Go to the documentation of w_flux 2.8.0 Download w_flux 2.8.0 archive
2.7.2 Jun 16, 2017 Go to the documentation of w_flux 2.7.2 Download w_flux 2.7.2 archive
2.7.1 Jun 13, 2017 Go to the documentation of w_flux 2.7.1 Download w_flux 2.7.1 archive
2.7.0 Apr 14, 2017 Go to the documentation of w_flux 2.7.0 Download w_flux 2.7.0 archive

All 22 versions...

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

The package version is not analyzed, because it does not support Dart 2. Until this is resolved, the package will receive a health and maintenance score of 0.

Issues and suggestions

Support Dart 2 in pubspec.yaml.

The SDK constraint in pubspec.yaml doesn't allow the Dart 2.0.0 release. For information about upgrading it to be Dart 2 compatible, please see https://www.dartlang.org/dart-2#migration.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=1.21.0 <2.0.0