• Stars
    star
    25
  • Rank 925,335 (Top 19 %)
  • Language
    Dart
  • License
    Other
  • Created about 9 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

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

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.

More Repositories

1

go-datastructures

A collection of useful, performant, and threadsafe Go datastructures.
Go
7,280
star
2

eva

A distributed database-system implementing an entity-attribute-value data-model that is time-aware, accumulative, and atomically consistent
Clojure
561
star
3

over_react

A library for building statically-typed React UI components using Dart.
Dart
420
star
4

react-dart

Dart Bindings for React JS
JavaScript
409
star
5

frugal

Thrift improved
Go
139
star
6

built_redux

an implementation of redux written in dart that enforces immutability
Dart
126
star
7

dart_dev

Centralized tooling for Dart projects. Consistent interface across projects. Easily configurable.
Dart
74
star
8

dart_codemod

A library that makes it easy to write and run automated code modifications on a codebase.
Dart
60
star
9

dependency_validator

A tool to help you find missing, under-promoted, over-promoted, and unused dependencies.
Dart
56
star
10

state_machine

Easily create a finite state machine and define legal state transitions. Listen to state entrances, departures, and transitions.
Dart
56
star
11

go-rest

A Go library that makes it easy to build a flexible and (mostly) unopinionated REST API with little ceremony.
Go
48
star
12

opentelemetry-dart

Dart
45
star
13

furious

Fast and modular async task library for Google App Engine.
Python
37
star
14

morphe

A Clojure utility for defining and applying aspects to function definitions.
Clojure
25
star
15

w_transport

A platform-agnostic transport library for sending and receiving data over HTTP and WebSocket.
Dart
23
star
16

aws-lambda-fsm-workflows

A Python framework for developing finite state machine-based workflows on AWS Lambda.
Python
21
star
17

dart_to_js_script_rewriter

A pub transformer that Rewrites Dart script tags to JavaScript script tags, eliminating 404s and speeding up initial loads. Use when building for deployment.
Dart
21
star
18

go-hystrimp

An ergonomic implementation of Hystrix fault-tolerance principles for Go developers.
Go
19
star
19

w_module

Base module classes with a well defined lifecycle for modular Dart applications.
Dart
18
star
20

fluri

Fluri is a fluent URI library for Dart built to make URI mutation easy.
Dart
18
star
21

gae-financials

Simple demo app to illustrate developing real world applications on Google App Engine.
Python
18
star
22

platform_detect

A library for detecting browser and platform type and version.
Dart
17
star
23

thrift-nats

A library that adds support for using NATS as a Thrift RPC transport.
Go
14
star
24

wf-uicomponents

Mobile-optimized, composable UI components that support a rich HTML5 user experience.
JavaScript
13
star
25

wGulp

Opinionated Suite of Gulp Tasks for JavaScript and TypeScript projects.
JavaScript
12
star
26

utiliva

A collection of helpful little utilities for Clojure.
Clojure
11
star
27

webdev_proxy

A simple HTTP proxy for the webdev serve command (a tool authored by the dart team) that adds support for rewriting certain requests, namely rewriting 404s to instead serve the root index (/index.html). This allows developers to work on browser applications (like our own) that use HTML5 routing while still being able to refresh and/or navigate directly to deep links.
JavaScript
11
star
28

r_tree

A recursive RTree library written in Dart.
Dart
10
star
29

scip-dart

Dart
10
star
30

opentracing_dart

This library is the Open Tracing API written in Dart. It is intended for use both on the server and in the browser.
Dart
10
star
31

w_common

A collection of helpful utilities for use in Dart projects.
Dart
10
star
32

styleguide

9
star
33

pdfjs_dart

Dart bindings for Mozilla's PDF.js library
JavaScript
7
star
34

wf-common

A collection of helpful utilities for use in JavaScript projects.
JavaScript
6
star
35

flowgraph

A Clojure library for fast, concurrent, asynchronous data processing using directed graphs. Decursus supports cyclic graphs. Though it is not distributed, it does have primitive tools for minimizing communication overhead in the event that some processing steps involve calls to distributed resources.
Clojure
6
star
36

over_react_test

A library for testing OverReact components
Dart
6
star
37

dart_transformer_utils

Utilities relating to code generation, Dart analyzer, logging, etc. for use in Pub transformers.
Dart
6
star
38

w_service

Dart
5
star
39

react_testing_library

Dart bindings for the JS dom-testing-library and react-testing-library packages, which provide simple and complete DOM/React testing utilities that encourage good testing practices.
Dart
5
star
40

tesserae

A Clojure library that abstracts over promises, futures, delays, etc. with chaining and cancellations.
Clojure
4
star
41

w-mobile-kit

A Swift library containing various custom UI components to provide functionality outside of the default libraries.
Swift
4
star
42

wf-grunt

Opinionated Suite of Grunt Tasks for JavaScript and TypeScript projects.
JavaScript
4
star
43

goverge

A golang multi package coverage reporting tool.
Python
3
star
44

workiva_analysis_options

Workiva's shared Dart static analysis options
Dart
3
star
45

autoPaw

JavaScript
3
star
46

over_react_codemod

Codemods to help consumers of over_react automate the migration of UI component code.
Dart
3
star
47

paw

A touch / touch gesture simulation library for JavaScript.
JavaScript
3
star
48

sockjs-dart-client

A Dart client library for SockJS.
Dart
3
star
49

lsif_indexer

Dart
2
star
50

eva-client-service

The Eva client service is an Eva peer which exposes Eva functionality to other languages through a REST interface.
Java
2
star
51

font_face_observer

Load and unload fonts in the browser with a Promise based API. Simple, small and efficient. It will use the FontFace api if available, otherwise it falls back to a Dart port of https://github.com/bramstein/fontfaceobserver
Dart
2
star
52

sockjs_client_wrapper

A Dart wrapper around the SockJS Client. Uses the js Dart package to interop with the JS lib.
JavaScript
2
star
53

eva-catalog

Provides a central repository (and client) for handling the configuration maps used to connect to EVA
Clojure
1
star
54

lazy-tables

A set of tools for lazy relational algebra
Clojure
1
star
55

test_html_builder

Dart builder that generates HTML files from templates for dart tests.
Dart
1
star
56

abide

A command line tool to manage analysis_options.yaml and check if it abides by requirements.
Dart
1
star
57

barometer

A thin clojure wrapper over Coda Hale's metrics library for the JVM.
Clojure
1
star
58

ichnaie

A handful of Clojure utilities for easing project integration with the OpenTracing API
Clojure
1
star
59

recide

Provides utilities for defining standard ex-info forms, as well as the capacity for checking at compile-time that they are being used as intended
Clojure
1
star