Skip to content

Commit 2a36301

Browse files
authored
Merge pull request #3 from KevinAst/feature-initialState
publish: v0.2.0 Added support for initialState
2 parents 1454886 + 710d6af commit 2a36301

19 files changed

+325
-241
lines changed

README.md

Lines changed: 46 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,10 @@ this example, and details the API.*
5252
```JavaScript
5353
import { reducerHash } from 'astx-redux-util';
5454

55-
const reduceWidget = reducerHash({
55+
export default reducerHash({
5656
"widget.edit": (widget, action) => action.widget,
5757
"widget.edit.close": (widget, action) => null,
58-
});
59-
60-
export default function widget(widget=null, action) {
61-
return reduceWidget(widget, action);
62-
}
58+
}, null);
6359
```
6460

6561

@@ -85,27 +81,23 @@ import * as AstxReduxUtil from 'astx-redux-util';
8581
import x from '../appReducer/x';
8682
import y from '../appReducer/y';
8783

88-
const reduceWidget =
89-
AstxReduxUtil.joinReducers(
90-
// FIRST: determine content shape (i.e. {} or null)
91-
AstxReduxUtil.reducerHash({
92-
"widget.edit": (widget, action) => action.widget,
93-
"widget.edit.close": (widget, action) => null
94-
}),
95-
96-
AstxReduxUtil.conditionalReducer(
97-
// SECOND: maintain individual x/y fields
98-
// ONLY when widget has content (i.e. is being edited)
99-
(widget, action, originalReducerState) => widget !== null,
100-
Redux.combineReducers({
101-
x,
102-
y
103-
}))
104-
);
105-
106-
export default function widget(widget=null, action) {
107-
return reduceWidget(widget, action);
108-
}
84+
export default AstxReduxUtil.joinReducers(
85+
// FIRST: determine content shape (i.e. {} or null)
86+
AstxReduxUtil.reducerHash({
87+
"widget.edit": (widget, action) => action.widget,
88+
"widget.edit.close": (widget, action) => null
89+
}),
90+
91+
AstxReduxUtil.conditionalReducer(
92+
// SECOND: maintain individual x/y fields
93+
// ONLY when widget has content (i.e. is being edited)
94+
(widget, action, originalReducerState) => widget !== null,
95+
Redux.combineReducers({
96+
x,
97+
y
98+
})),
99+
100+
null); // initialState
109101
```
110102

111103
### Full Example
@@ -133,39 +125,35 @@ import x from '../appReducer/x';
133125
import y from '../appReducer/y';
134126
import Widget from '../appReducer/Widget';
135127

136-
const reduceWidget =
137-
AstxReduxUtil.joinReducers(
138-
// FIRST: determine content shape (i.e. {} or null)
139-
AstxReduxUtil.reducerHash({
140-
"widget.edit": (widget, action) => action.widget,
141-
"widget.edit.close": (widget, action) => null
142-
}),
143-
144-
AstxReduxUtil.conditionalReducer(
145-
// NEXT: maintain individual x/y fields
146-
// ONLY when widget has content (i.e. is being edited)
147-
(widget, action, originalReducerState) => widget !== null,
148-
AstxReduxUtil.joinReducers(
149-
Redux.combineReducers({
150-
x,
151-
y,
152-
curHash: placeboReducer
153-
}),
154-
AstxReduxUtil.conditionalReducer(
155-
// LAST: maintain curHash
156-
// ONLY when widget has content (see condition above) -AND- has changed
157-
(widget, action, originalReducerState) => originalReducerState !== widget,
158-
(widget, action) => {
159-
widget.curHash = Widget.hash(widget); // OK to mutate (because of changed instance)
160-
return widget;
161-
})
162-
)
128+
export default AstxReduxUtil.joinReducers(
129+
// FIRST: determine content shape (i.e. {} or null)
130+
AstxReduxUtil.reducerHash({
131+
"widget.edit": (widget, action) => action.widget,
132+
"widget.edit.close": (widget, action) => null
133+
}),
134+
135+
AstxReduxUtil.conditionalReducer(
136+
// NEXT: maintain individual x/y fields
137+
// ONLY when widget has content (i.e. is being edited)
138+
(widget, action, originalReducerState) => widget !== null,
139+
AstxReduxUtil.joinReducers(
140+
Redux.combineReducers({
141+
x,
142+
y,
143+
curHash: placeboReducer
144+
}),
145+
AstxReduxUtil.conditionalReducer(
146+
// LAST: maintain curHash
147+
// ONLY when widget has content (see condition above) -AND- has changed
148+
(widget, action, originalReducerState) => originalReducerState !== widget,
149+
(widget, action) => {
150+
widget.curHash = Widget.hash(widget); // OK to mutate (because of changed instance)
151+
return widget;
152+
})
163153
)
164-
);
154+
),
165155

166-
export default function widget(widget=null, action) {
167-
return reduceWidget(widget, action);
168-
}
156+
null); // initialState
169157

170158
// placeboReducer WITH state initialization (required for Redux.combineReducers())
171159
function placeboReducer(state=null, action) {

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "astx-redux-util",
3-
"version": "0.1.0",
3+
"version": "0.2.0",
44
"description": "Several redux reducer composition utilities.",
55
"main": "lib/index.js",
66
"browser": {
@@ -103,6 +103,8 @@
103103
"webpack": "^2.2.1"
104104
},
105105
"dependencies": {
106-
"lodash.identity": "^3.0.0"
106+
"lodash.identity": "^3.0.0",
107+
"lodash.isfunction": "^3.0.8",
108+
"lodash.last": "^3.0.0"
107109
}
108110
}

src/docs/guide/conceptConditional.md

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,18 @@ This can be accomplished through the {@link conditionalReducer} utility.
99

1010
```JavaScript
1111
import * as Redux from 'redux';
12+
import identity from 'lodash.identity';
1213
import * as AstxReduxUtil from 'astx-redux-util';
1314
import x from '../appReducer/x';
1415
import y from '../appReducer/y';
1516

16-
const reduceWidget =
17-
AstxReduxUtil.conditionalReducer(
18-
// conditionally apply when action.type begins with 'widget.edit'
19-
(curState, action, originalReducerState) => action.type.startsWith('widget.edit'),
20-
Redux.combineReducers({
21-
x,
22-
y
23-
}));
24-
25-
export default function widget(widget={}, action) {
26-
return reduceWidget(widget, action);
27-
}
17+
export default AstxReduxUtil.conditionalReducer(
18+
// conditionally apply when action.type begins with 'widget.edit'
19+
(curState, action, originalReducerState) => action.type.startsWith('widget.edit'),
20+
Redux.combineReducers({
21+
x,
22+
y
23+
}), identity, {});
2824
```
2925

3026
Here we only invoke the supplied reducer
@@ -34,10 +30,17 @@ example, our action types are organized with a federated namespace, so
3430
it is easy to isolate which actions will impact various parts of our
3531
state.
3632

37-
**Note:** Because we did not supply "elseReducerFn" to {@link
38-
conditionalReducer} (the third parameter), the default [identity
39-
function](https://lodash.com/docs#identity) is used for the else
40-
condition, in essence retaining the same state for a falsy directive.
33+
**Please Note** that a `{}` {@link InitialState} value is applied in
34+
this reduction, which provides the fall-back state value during the
35+
state initialization boot-strap process.
36+
37+
**Also Note:** that normally it is not necessary to supply the
38+
`elseReducerFn` {@link conditionalReducer} parameter (the third),
39+
because it defaults to the [identity
40+
function](https://lodash.com/docs#identity) function, which retains
41+
the state for a falsy directive. In this case however, we had to
42+
manually pass the identity function, in order to supply the subsequent
43+
{@link InitialState} parameter.
4144

4245
**More to Come:** This example is merely intended to introduce you to
4346
the concept of conditional reduction. It is somewhat "contrived",

src/docs/guide/conceptHash.md

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,20 @@ action.type.
2828
```
2929
import { reducerHash } from 'astx-redux-util';
3030
31-
const reduceWidget = reducerHash({
31+
export default reducerHash({
3232
"widget.edit": (widget, action) => action.widget,
3333
"widget.edit.close": (widget, action) => null,
34-
});
35-
36-
export default function widget(widget=null, action) {
37-
return reduceWidget(widget, action);
38-
}
34+
}, null);
3935
```
4036

4137
Not only is the conditional logic better encapsulated, but the default
4238
pass-through logic is automatically applied (using the [identity
4339
function](https://lodash.com/docs#identity)), passing through the
4440
original state when no action.type is acted on.
4541

46-
47-
**Please Note** that because {@link reducerHash} is a higher-order
48-
creator function, it is invoked outside the scope of the widget()
49-
reducer. This is an optimization, so as to not incur the creation
50-
overhead on each reducer invocation.
42+
**Please Note** that a `null` {@link InitialState} value is applied in
43+
this reduction, which provides the fall-back state value during the
44+
state initialization boot-strap process.
5145

5246
**Also Note** that because {@link reducerHash} is so central to the
5347
rudimentary aspects of reduction, it is common to provide a

src/docs/guide/conceptJoin.md

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -97,27 +97,23 @@ import * as AstxReduxUtil from 'astx-redux-util';
9797
import x from '../appReducer/x';
9898
import y from '../appReducer/y';
9999

100-
const reduceWidget =
101-
AstxReduxUtil.joinReducers(
102-
// FIRST: determine content shape (i.e. {} or null)
103-
AstxReduxUtil.reducerHash({
104-
"widget.edit": (widget, action) => action.widget,
105-
"widget.edit.close": (widget, action) => null
106-
}),
107-
108-
AstxReduxUtil.conditionalReducer(
109-
// SECOND: maintain individual x/y fields
110-
// ONLY when widget has content (i.e. is being edited)
111-
(widget, action, originalReducerState) => widget !== null,
112-
Redux.combineReducers({
113-
x,
114-
y
115-
}))
116-
);
117-
118-
export default function widget(widget=null, action) {
119-
return reduceWidget(widget, action);
120-
}
100+
export default AstxReduxUtil.joinReducers(
101+
// FIRST: determine content shape (i.e. {} or null)
102+
AstxReduxUtil.reducerHash({
103+
"widget.edit": (widget, action) => action.widget,
104+
"widget.edit.close": (widget, action) => null
105+
}),
106+
107+
AstxReduxUtil.conditionalReducer(
108+
// SECOND: maintain individual x/y fields
109+
// ONLY when widget has content (i.e. is being edited)
110+
(widget, action, originalReducerState) => widget !== null,
111+
Redux.combineReducers({
112+
x,
113+
y
114+
})),
115+
116+
null); // initialState
121117
```
122118

123119
Here the joinReducers combines multiple reducers together as one.
@@ -133,10 +129,5 @@ Here the joinReducers combines multiple reducers together as one.
133129
**Reducer composition provides a more elegant solution that is
134130
purely functional in nature.**
135131

136-
**Please Note** that the higher-order reducer functions are invoked
137-
outside the scope of the widget() reducer, as an optimization, so as
138-
to not incur the creation overhead on each reducer invocation.
139-
140-
141132

142133
[Redux.combineReducers]: http://redux.js.org/docs/api/combineReducers.html

src/docs/guide/fullExample.md

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -32,39 +32,35 @@ import x from '../appReducer/x';
3232
import y from '../appReducer/y';
3333
import Widget from '../appReducer/Widget';
3434

35-
const reduceWidget =
36-
AstxReduxUtil.joinReducers(
37-
// FIRST: determine content shape (i.e. {} or null)
38-
AstxReduxUtil.reducerHash({
39-
"widget.edit": (widget, action) => action.widget,
40-
"widget.edit.close": (widget, action) => null
41-
}),
42-
43-
AstxReduxUtil.conditionalReducer(
44-
// NEXT: maintain individual x/y fields
45-
// ONLY when widget has content (i.e. is being edited)
46-
(widget, action, originalReducerState) => widget !== null,
47-
AstxReduxUtil.joinReducers(
48-
Redux.combineReducers({
49-
x,
50-
y,
51-
curHash: placeboReducer
52-
}),
53-
AstxReduxUtil.conditionalReducer(
54-
// LAST: maintain curHash
55-
// ONLY when widget has content (see condition above) -AND- has changed
56-
(widget, action, originalReducerState) => originalReducerState !== widget,
57-
(widget, action) => {
58-
widget.curHash = Widget.hash(widget); // OK to mutate (because of changed instance)
59-
return widget;
60-
})
61-
)
35+
export default AstxReduxUtil.joinReducers(
36+
// FIRST: determine content shape (i.e. {} or null)
37+
AstxReduxUtil.reducerHash({
38+
"widget.edit": (widget, action) => action.widget,
39+
"widget.edit.close": (widget, action) => null
40+
}),
41+
42+
AstxReduxUtil.conditionalReducer(
43+
// NEXT: maintain individual x/y fields
44+
// ONLY when widget has content (i.e. is being edited)
45+
(widget, action, originalReducerState) => widget !== null,
46+
AstxReduxUtil.joinReducers(
47+
Redux.combineReducers({
48+
x,
49+
y,
50+
curHash: placeboReducer
51+
}),
52+
AstxReduxUtil.conditionalReducer(
53+
// LAST: maintain curHash
54+
// ONLY when widget has content (see condition above) -AND- has changed
55+
(widget, action, originalReducerState) => originalReducerState !== widget,
56+
(widget, action) => {
57+
widget.curHash = Widget.hash(widget); // OK to mutate (because of changed instance)
58+
return widget;
59+
})
6260
)
63-
);
61+
),
6462

65-
export default function widget(widget=null, action) {
66-
return reduceWidget(widget, action);
67-
}
63+
null); // initialState
6864

6965
// placeboReducer WITH state initialization (required for Redux.combineReducers())
7066
function placeboReducer(state=null, action) {

0 commit comments

Comments
 (0)