Skip to content

Commit 15670e4

Browse files
committed
Docs updates
1 parent b3ef9d9 commit 15670e4

File tree

5 files changed

+80
-34
lines changed

5 files changed

+80
-34
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
# 0.3
2+
3+
### **BREAKING CHANGE:** New component mounting API
4+
5+
In light of the architectural changes in 0.2, and because the old API was quite confusing, we've designed a new API for mounting components. The `mounter` function has been eliminated and replaced with an imperative API for mounting and unmounting.
6+
7+
For those managing their entire state tree with `redux-components`, the transition should be easy: replace your single `mountComponent` statement with the new `mountRootComponent`, which has the same argument signature.
8+
9+
Those with more complex state tree designs will want to [read the docs](https://wcjohnson.gitbooks.io/redux-components/content/docs/API/mountComponent.html).
10+
11+
### ReduxComponentClasses can now be used as mixins.
12+
13+
A `ReduxComponentClass` (the object returned by `createClass`) can now be used as a mixin on any other class. This can be used to simulate class inheritance in many use cases.
14+
15+
### actionDispatchers now support falsy return values
16+
17+
In 0.2, `actionDispatchers` were added to directly dispatch actions to a mounted component's store. They were required to return a valid Redux action. Now they may return a falsy value, in which case no action will be dispatched.
18+
19+
### Minor changes and fixes
20+
21+
- Redux is now listed as a dependency rather than a peerDependency.
22+
- The internal `__reducerMap` variable on `SubtreeMixin` instances has been removed.
23+
124
# 0.2
225

326
This is a major release that brings some changes that my team is excited about.

docs/API/SubtreeMixin.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ When the parent component is mounted, child components are instantiated using `c
2020
In vanilla Redux, a root reducer is often the result of a `combineReducers` over several reducers handling separate branches of app state. In redux-components, the corresponding pattern is a component using `SubtreeMixin` to combine several subcomponents:
2121

2222
```coffeescript
23-
createClass = require 'redux-components/createClass'
24-
SubtreeMixin = require 'redux-components/SubtreeMixin'
23+
{ createStore } = require 'redux'
24+
{ createClass, SubtreeMixin, mountRootComponent } = require 'redux-components'
2525
Foo = require 'MyComponents/Foo', ...
2626

2727
RootComponent = createClass {
@@ -35,6 +35,13 @@ RootComponent = createClass {
3535
...
3636
}
3737
}
38+
39+
rootComponent = new RootComponent
40+
41+
# Create store with empty reducer
42+
store = createStore( (x) -> x )
43+
# Generate the reducer from the component tree and attach it.
44+
mountRootComponent(store, rootComponent)
3845
```
3946

4047
## Details
@@ -43,4 +50,4 @@ When a component with a `SubtreeMixin` enters `componentWillMount`, it calls `ge
4350

4451
## Notes
4552

46-
> `SubtreeMixin` is an optimized implementation for the most common use case: nodes with a static shape. This is when the keys and subcomponent classes returned by getSubtree do not depend on the Redux state or change throughout the app lifecycle. For subtrees that are stateful or dynamic, see `DynamicSubtreeMixin`.
53+
> `SubtreeMixin` is an optimized implementation for the most common use case: nodes with a static shape. This is when the keys and subcomponent classes returned by getSubtree do not depend on the Redux state or change throughout the app lifecycle. For subtrees that are stateful or dynamic, see the `redux-components-map` project.

docs/API/mountComponent.md

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,29 @@
11
# mountComponent
2-
```coffeescript
3-
{ mountComponent } = require 'redux-components'
4-
mountComponent: (
5-
store = { getState, dispatch, subscribe, replaceReducer },
6-
componentInstance = instanceof ReduxComponent,
7-
path = [string|number, ...],
8-
mounter = (store, componentInstance) ->
9-
) ->
10-
```
11-
Mounts a component instance to the redux state tree. `store` is a reference to the Redux store. The `componentInstance` is the component instance to be attached to the tree. The `path` is an array path from the root node of the state tree to the node at which this component will be mounted.
12-
13-
The `mounter` is a function that will be called as the component is mounting, and additionally whenever the subtree managed by this component requests a change in reducer. It should have the effect of replacing the store's root reducer via `store.replaceReducer()` as appropriate.
142

153
## State tree design
164

17-
### Root managed by redux-components; connected subtrees
5+
Broadly speaking, there are two ways to manage your Redux state tree using redux-components. You can let redux-components manage the root of your tree (as well as all subnodes) or your state tree can be managed manually, with redux-components being mounted at one or more subnodes of the state tree.
6+
7+
We discuss both of these cases.
188

19-
In this case, a redux-component instance will be mounted at the root of the state tree, and hence will manage the root reducer. You will only ever call `mountComponent` once, to connect this root component. Trees of subcomponents descending from the root will be managed by `SubtreeMixin`.
9+
### redux-component at the root
2010

21-
We expect this to be the typical (or if not typical, then certainly simplest) case and so we provide a default implementation of `mounter` for this scenario:
11+
The easiest way to use redux-components is to let it manage the root node of your state tree. In this case, a redux-component instance will be mounted at the root of the state tree, and hence will manage the root reducer. To do this, use `mountRootComponent`.
2212

2313
```coffeescript
24-
mounter = (store, componentInstance) ->
25-
store.replaceReducer(componentInstance.reducer)
14+
{ mountRootComponent } = require 'redux-components'
15+
mountRootComponent: (
16+
store = { getState, dispatch, subscribe, replaceReducer },
17+
componentInstance = instanceof ReduxComponent
18+
) ->
2619
```
20+
`mountRootComponent` attaches a ReduxComponent to the root of the state tree, allowing it to manage the entire tree. `store` is a reference to the Redux store. The `componentInstance` is the component instance to be attached to the tree.
21+
22+
Internally, this function uses `store.replaceReducer()` to attach the reducer of the `componentInstance` to the Redux store, allowing it to manage the store's whole state.
2723

2824
If this is your use case, you will initialize your store like this:
2925
```coffeescript
30-
mountComponent = require 'redux-components/mountComponent'
31-
createClass = require 'redux-components/createClass'
26+
{ mountRootComponent, createClass } = require 'redux-components'
3227
{ createStore } = require 'redux'
3328

3429
RootComponentClass = createClass {
@@ -39,17 +34,40 @@ rootComponent = new RootComponentClass
3934
# Create store with empty reducer
4035
store = createStore( (x) -> x )
4136
# Generate the reducer from the component tree and attach it.
42-
mountComponent(store, rootComponent)
37+
mountRootComponent(store, rootComponent)
4338
```
4439

4540
> * When using this approach, you can still attach reducers not managed by redux-components to nodes of your state tree beneath the root. Use `SubtreeMixin`.
46-
> * If you need to use a higher-order reducer at the root of your state tree, you must provide a `mounter` that wraps `componentInstance.reducer` in your higher-order reducer before attaching it to the store.
47-
> * Don't disconnect subtrees of redux-components! Every redux-component should have a parent that is a redux-component, except the unique root component at the top of the tree. If this is not so, you are in the (more difficult) case described below.
4841
49-
### Unmanaged root and/or disconnected subtrees
42+
### Manual mounting
43+
44+
If redux-components does not manage your root reducer, then you will need to mount and unmount components manually using the following API:
45+
46+
```coffeescript
47+
{ willMountComponent, didMountComponent, willUnmountComponent } = require 'redux-components'
48+
willMountComponent: (
49+
store = { getState, dispatch, subscribe, replaceReducer },
50+
componentInstance = instanceof ReduxComponent
51+
path = [string|number, ...]
52+
) -> reducer
53+
54+
didMountComponent: (
55+
componentInstance = instanceof ReduxComponent
56+
) ->
57+
58+
willUnmountComponent: (
59+
componentInstance = instanceof ReduxComponent
60+
) ->
61+
```
62+
63+
The manual mounting process works as follows: first you call `willMountComponent(store, componentInstance, path)`, providing the Redux `store`, the `componentInstance` you wish to mount, as well as the `path` from the root node of the store to the spot where the component will be mounted. The `path` is provided in the array form that would be used by `lodash.get()`.
64+
65+
`willMountComponent` will return a reducer, which you must then attach to your state tree at the given `path` using something like `store.replaceReducer()`. Once the reducer is in place, you must call `didMountComponent(componentInstance)` on the component in order to honor the redux-components lifecycle contract.
66+
67+
> * Do not manually mount components beneath redux-components that manage children, such as `SubtreeMixin` nodes or `redux-components-map`. This will bypass the internal logic of those components and almost certainly break your reducer tree. Use the correct APIs of the parent component to add child nodes beneath these components.
5068
51-
We strongly recommend allowing redux-components to manage your root reducer if possible. It makes everything work better. But maybe this is impossible for your use case.
69+
### Manual unmounting
5270

53-
If so, you can implement a design where you will manage your own state tree from the root, with one or more subtrees managed by redux-components. You will call `mountComponent` for each such subtree. For each component you mount, you must provide your own implementation of `mounter` that will rebuild and reattach the root reducer, taking into account the fact that the `mountedInstance`'s reducer may have changed.
71+
If you want to unmount a manually-mounted component, you should call `willUnmountComponent(componentInstance)` on it first. This will invoke the `willUnmount` method as required by redux-components' lifecycle contract, as well as replacing the reducer for the component with the identity.
5472

55-
> If you have multiple disconnected subtrees managed by redux-components, the `mounter` for each subtree must be aware of the others and reattach their reducers correctly!
73+
You must then manually patch up the state tree. (e.g. by calling `replaceReducer()` to remove the manually-mounted reducer) Such is the nature of manual mounting, and why we recommend letting redux-components manage your root nodes.

docs/Advanced/DynamicReducer.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ An example is the `ComponentMap` class implemented in [redux-component-map](http
1212

1313
In order to implement this behavior, it is necessary to define a new reducer function each time the tree of components changes, because the reducer function is a composition of other functions and the composition depends on the shape of the tree. This is the typical use case for which dynamic reducers were developed.
1414

15-
Dynamic reducers are dangerous in general. Most of the time someone needs a dynamic reducer, it is basically to implement `Map` or something like it. If that's you, consider redux-component-map before writing your own.
15+
Dynamic reducers are dangerous in general. Most of the time someone needs a dynamic reducer, it is basically to implement `Map` or something like it. If that's you, consider `redux-components-map` before writing your own.
1616

1717
## How do I create a component with a dynamic reducer?
1818

package.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "redux-components",
3-
"version": "0.2.3",
3+
"version": "0.3.0",
44
"description": "A component model for Redux state trees based on the React.js component model.",
55
"keywords": [
66
"redux",
@@ -51,9 +51,7 @@
5151
},
5252
"dependencies": {
5353
"invariant": "^2.2.2",
54-
"symbol-observable": "^1.0.4"
55-
},
56-
"peerDependencies": {
54+
"symbol-observable": "^1.0.4",
5755
"redux": "^3.6.0"
5856
}
5957
}

0 commit comments

Comments
 (0)