Skip to content

Commit

Permalink
Merge pull request #2 from KevinAst/feature-initial
Browse files Browse the repository at this point in the history
publish: v0.1.0 Initial Release
  • Loading branch information
KevinAst authored Mar 8, 2017
2 parents a45b383 + 5b1587d commit 3fedab4
Show file tree
Hide file tree
Showing 47 changed files with 1,609 additions and 474 deletions.
13 changes: 12 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
{
"presets": ["es2015", "stage-1"]
"presets": ["es2015", "stage-1"],
"env": {
"commonjs": {
"plugins": [
["transform-es2015-modules-commonjs", { "loose": true }]
]
},
"es": {
"plugins": [
]
}
}
}
23 changes: 23 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"env": {
"es6": true,
"browser": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module"
},
"globals": {
"describe": true, // describe() is part of our unit test framework
"it": true // it() is part of our unit test framework
},
"rules": {
"strict": ["error", "never"], // ES6 Modules imply a 'use strict'; ... specifying this is redundant
"indent": ["off", 2], // allow any indentation
"no-unused-vars": ["error", {"args": "none"}], // allow unsed parameter declaration
"linebreak-style": "off", // allow both unix/windows carriage returns
"quotes": "off", // allow single or double quotes string literals
"semi": ["error", "always"] // enforce semicolons
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

# bundled distribution (generated via "npm run build")
/dist/
/lib/
/es/

# documentation (generated via "npm run docs")
/docs/
Expand Down
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
language: node_js
node_js:
- "6"
- "7"
- node # current node version (may be duplicate, but that's OK)
script:
- npm run prepublish # lint, clean, build (bundles), test (bundles)
branches:
except:
- gh-pages
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Change Log

The [astx-redux-util](https://astx-redux-util.js.org) project adheres
to [Semantic Versioning](http://semver.org/).

Each release, along with migration instructions, is documented on the
[Github Releases](https://github.com/KevinAst/astx-redux-util/releases) page.
File renamed without changes.
173 changes: 155 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
# astx-redux-util

The [astx-redux-util] library provides several redux reducer composition
utilities, of which the most prevalent is **reducerHash()** which
allows you to displace the dreaded switch statement ... **but there is
much more!**
The [astx-redux-util] library promotes several redux reducer
composition utilities, which blend multiple reducers together forming
a richer abstraction through functional decomposition
(i.e. higher-order functions).

Reducer composition is not new. Redux itself provides the innovative
[combineReducers](http://redux.js.org/docs/api/combineReducers.html)
utility which allows you to fuse individual reducers together to build
up the overall shape of your application state.

## Documentation
The most prevalent [astx-redux-util] utility is **reducerHash()**,
which lets you combine sub-reducers in such a way as to eliminate
the switch statement commonly used to delineate action type.

Comprehensive documentation can be found at: [astx-redux-util].
**Additionally**, [astx-redux-util] promotes other reducer compositions that
can be used in conjunction with one another.

<!--- Badges for CI Builds --->
<!--- TODO: ?? point to master branch --->
[![Build Status](https://travis-ci.org/KevinAst/astx-redux-util.svg?branch=master)](https://travis-ci.org/KevinAst/astx-redux-util)
[![NPM Version Badge](https://img.shields.io/npm/v/astx-redux-util.svg)](https://www.npmjs.com/package/astx-redux-util)


## Comprehensive Documentation

Complete documentation can be found at
https://astx-redux-util.js.org/, which includes both **API** details,
and a **User Guide** with full and thorough **examples**!


## Install
Expand All @@ -20,26 +39,144 @@ npm install --save astx-redux-util

## Usage

### Basics

The following example uses **reducerHash()** to combine a set of
sub-reducer functions (indexed by the standard action.type),
eliminating the switch statement commonly used to delineate action
type.

**Don't miss the [astx-redux-util] documentation**, *which fully explores
this example, and details the API.*

```JavaScript
import {reducerHash} from 'astx-redux-util';
import { reducerHash } from 'astx-redux-util';

const reduceWidget = reducerHash({
"widget.edit": (widget, action) => action.widget,
"widget.edit.close": (widget, action) => null,
});

export default function widget(widget=null, action) {
return reduceWidget(widget, action);
}
```

const myReducer = reducerHash({
[ActionType.widget.edit] (widget, action) => action.widget,
[ActionType.widget.edit.close] (widget, action) => null,
});

export default function widget(widget=null, action) {
return myReducer(widget, action);
}
### Joining Reducers

Building on the previous example, our widget now takes on more detail:
- we manage x/y properties (through the standard
[combineReducers](http://redux.js.org/docs/api/combineReducers.html))
- the widget itself can take on a null value (an indication it is NOT
being edited)

We manage these new requirements by combining multiple reducers
through a functional decomposition (as opposed to procedural code).
To accomplish this, we add to our repertoire by introducing
**joinReducers()** and **conditionalReducer()**.

**Don't miss the [astx-redux-util] documentation**, *which fully explores
this example, and details the API.*

```JavaScript
import * as Redux from 'redux';
import * as AstxReduxUtil from 'astx-redux-util';
import x from '../appReducer/x';
import y from '../appReducer/y';

const reduceWidget =
AstxReduxUtil.joinReducers(
// FIRST: determine content shape (i.e. {} or null)
AstxReduxUtil.reducerHash({
"widget.edit": (widget, action) => action.widget,
"widget.edit.close": (widget, action) => null
}),

AstxReduxUtil.conditionalReducer(
// SECOND: maintain individual x/y fields
// ONLY when widget has content (i.e. is being edited)
(widget, action, originalReducerState) => widget !== null,
Redux.combineReducers({
x,
y
}))
);

export default function widget(widget=null, action) {
return reduceWidget(widget, action);
}
```

### Full Example

Building even more on the prior examples:
- our widget adds a curHash property (which is a determinate of
whether application content has changed)

## Don't Miss
We manage this new property in the parent widget reducer, because it
has a unique vantage point of knowing when the widget has changed
(under any circumstance, regardless of how many properties are
involved).

We accomplish this by simply combining yet another reducer (using a
functional approach). This also demonstrates how **composition can be
nested!**

**Don't miss the [astx-redux-util] documentation**, *which fully explores
this example, and details the API.*

```JavaScript
import * as Redux from 'redux';
import * as AstxReduxUtil from 'astx-redux-util';
import x from '../appReducer/x';
import y from '../appReducer/y';
import Widget from '../appReducer/Widget';

const reduceWidget =
AstxReduxUtil.joinReducers(
// FIRST: determine content shape (i.e. {} or null)
AstxReduxUtil.reducerHash({
"widget.edit": (widget, action) => action.widget,
"widget.edit.close": (widget, action) => null
}),

AstxReduxUtil.conditionalReducer(
// NEXT: maintain individual x/y fields
// ONLY when widget has content (i.e. is being edited)
(widget, action, originalReducerState) => widget !== null,
AstxReduxUtil.joinReducers(
Redux.combineReducers({
x,
y,
curHash: placeboReducer
}),
AstxReduxUtil.conditionalReducer(
// LAST: maintain curHash
// ONLY when widget has content (see condition above) -AND- has changed
(widget, action, originalReducerState) => originalReducerState !== widget,
(widget, action) => {
widget.curHash = Widget.hash(widget); // OK to mutate (because of changed instance)
return widget;
})
)
)
);

export default function widget(widget=null, action) {
return reduceWidget(widget, action);
}

// placeboReducer WITH state initialization (required for Redux.combineReducers())
function placeboReducer(state=null, action) {
return state;
}
```

For a more complete and thorough example of how these utilities can be
used, don't miss the **Full Documentation** at [astx-redux-util]
which includes a **Comprehensive Example**.
This represents a very comprehensive example of how **Reducer
Composition** can **simplify your life**! We have combined multiple
reducers into one, applying conditional logic as needed through
functional decomposition!


[astx-redux-util]: https://astx-redux-util.js.org/
Loading

0 comments on commit 3fedab4

Please sign in to comment.