+ );
+}
+
+const hoc = compose(
+ withRPCRedux('greet'),
+ connect(({greeting, loading, error}) => ({greeting, loading, error})),
+);
+export default hoc(Example);
+```
+
+---
+
+### Setup
```js
// src/main.js
@@ -25,8 +82,9 @@ import RPC, {RPCToken, RPCHandlersToken} from 'fusion-plugin-rpc-redux-react';
import {FetchToken} from 'fusion-tokens';
import fetch from 'unfetch';
-import reducer from './reducer';
-import handlers from './rpc';
+import root from './components/index.js'
+import reducer from './redux/index.js';
+import handlers from './rpc/index.js';
export default () => {
const app = new App(root);
@@ -39,51 +97,133 @@ export default () => {
app.register(ReduxToken, Redux);
app.register(ReducerToken, reducer);
}
+```
-// src/reducer.js
-import {createRPCReducer} from 'fusion-plugin-rpc-redux-react';
-export default createRPCReducer('increment', {
- start: (state, action) => ({count: state.count, loading: true, error: ''});
- success: (state, action) => ({count: action.payload.count, loading: false, error: ''});
- failure: (state, action) => ({count: state.count, loading: false, error: action.payload.error});
-});
+---
-// src/rpc.js
-export default {
- getCount() {
- return 0;
- },
- increment() {
- return db.query(/* ... */).then(n => ({count: n}));
- }
-}
+### API
-// src/root.js
-import React from 'react';
+#### Registration API
+
+##### `RPC`
+
+```js
+import RPC from 'fusion-plugin-rpc-redux-react';
+```
+
+The plugin. Typically it should be registered to [`RPCToken`](#rpctoken). Installs an RPC provider at the root of the React tree.
+
+###### `RPCToken`
+
+```js
+import {RPCToken} from 'fusion-plugin-rpc-redux-react';
+```
+
+The canonical token for the RPC plugin. Typically, it should be registered with the [RPC](#rpc) plugin.
+
+#### Dependencies
+
+##### `UniversalEventsToken`
+
+Required. See [https://github.com/fusionjs/fusion-plugin-universal-events#api](https://github.com/fusionjs/fusion-plugin-universal-events#api)
+
+##### `RPCHandlersToken`
+
+```js
+import {RPCHandlersToken} from 'fusion-plugin-rpc-redux-react';
+```
+
+Configures what RPC handlers exist. Required. Server-only.
+
+###### Types
+
+```flow
+type RPCHandlers = Object any>
+```
+
+You can register a value of type `RPCHandlers` or a Plugin that provides a value of type `RPCHandlers`.
+
+##### `FetchToken`
+
+Required. Browser-only. See [https://github.com/fusionjs/fusion-tokens#fetchtoken](https://github.com/fusionjs/fusion-tokens#fetchtoken)
+
+##### `ReduxToken`
+
+Required. See [https://github.com/fusionjs/fusion-plugin-react-redux](https://github.com/fusionjs/fusion-plugin-react-redux)
+
+##### `ReducerToken`
+
+Required. See [https://github.com/fusionjs/fusion-plugin-react-redux](https://github.com/fusionjs/fusion-plugin-react-redux)
+
+---
+
+#### `withRPCRedux`
+
+```js
import {withRPCRedux} from 'fusion-plugin-rpc-redux-react';
-import {connect} from 'react-redux';
-import {compose} from 'redux';
+```
-function Example({count, loading, error, increment}) {
- return (
-
-
Count: {count}
-
-
-
- {loading && 'Loading...'}
- {error}
-
- );
-}
+Creates a higher order component with a prop mapped to the given RPC method. It can additionally configure the mapped method with parameters from state or from a transformation function.
-const hoc = compose(
- withRPCRedux('increment'),
- connect(({count, loading, error}) => ({count, loading, error})),
-);
-export default hoc(Example);
+```js
+const hoc:HOC = withRPCRedux(rpcId: string, {
+ propName: ?string,
+ mapStateToParams: ?(state: any) => any,
+ transformParams: ?(params: any) => any,
+})
+```
+
+* `rpcId: string` - The name of the RPC method to expose in the component's props
+* `propName: ?string` - Optional. The name of the prop. Defaults to the same as `rpcId`
+* `mapStateToParams: ?(state: any) => any` - populate the RPC request with parameters from Redux state
+* `transformParams: ?(params: any) => any` - transforms the params
+* returns `hoc: Component => Component`
+
+#### `withRPCReactor`
+
+```js
+import {withRPCReactor} from 'fusion-plugin-rpc-redux-react';
+```
+
+Creates a higher order component by colocating global reducers to the component
+
+```js
+const hoc:HOC = withRPCReactor(rpcId: string, {
+ start: ?(state: any, action: Object) => any,
+ success: ?(state: any, action: Object) => any,
+ failure: ?(state: any, action: Object) => any,
+}, {
+ propName: ?string
+ mapStateToParams: ?(state: any) => any,
+ transformParams: ?(params: any) => any,
+});
+```
+
+* `rpcId: string` - The name of the RPC method to expose in the component's props
+* `start: ?(state: any, action: Object) => any` - A reducer to run when the RPC call is made
+* `success: ?(state: any, action: Object) => any` - A reducer to run when the RPC call succeeds
+* `failure: ?(state: any, action: Object) => any` - A reducer to run when the RPC call fails
+* `propName: ?string` - Optional. The name of the prop. Defaults to the same as `rpcId`
+* `mapStateToParams: ?(state: any) => any` - populate the RPC request with parameters from Redux state
+* `transformParams: ?(params: any) => any` - transforms the params
+* returns `hoc: Component => Component`
+
+#### mock
+
+```js
+import {mock as MockRPC} from 'fusion-plugin-rpc-redux-react';
```
+The package also exports a mock RPC plugin which can be useful for testing. For example:
+
+```js
+app.register(RPCToken, mock);
+```
+
+---
+
+### Other examples
+
### Usage with Reactors
[`redux-reactors`](https://github.com/ganemone/redux-reactors) is a library that allows you to colocate Redux actions and reducers
@@ -164,7 +304,7 @@ Below is an example of consuming the state and RPC methods that are made availab
import React from 'react';
import {connect} from 'react-redux';
import {compose} from 'redux';
-import {incrementReactor} from './reactors/increment.js'
+import {incrementReactor} from './reactors/increment.js';
function Example({count, loading, error, increment}) {
return (
@@ -181,7 +321,7 @@ function Example({count, loading, error, increment}) {
const hoc = compose(
incrementReactor,
- connect(({count, loading, error}) => ({count, loading, error})),
+ connect(({count, loading, error}) => ({count, loading, error}))
);
export default hoc(Example);
```
@@ -195,73 +335,3 @@ Another point worth mentioning is that with traditional reducers, it's possible
Reactors, on the other hand, colocate a single reducer to a single action, so all state transformations pertaining to any given action are handled by a single function. This comes at the cost of flexibility: it's no longer possible to refactor the shape of the state tree without changing every affectd reducer, and it's also possible to affect unrelated parts of the state tree, for example missing properties due to an overly conservative object assignment.
However doing large refactors to the shape of the state tree isn't necessarily all that common and it's often more intuitive to see all possible state transformations for a given action in a single place. In addition to creating less boilerplate, this pattern leads to similarly intuitive tests that are also colocated by action.
-
----
-
-### API
-
-#### Dependency registration
-
-```js
-// src/main.js
-import {RPCHandlersToken} from 'fusion-plugin-rpc';
-import UniversalEvents, {UniversalEventsToken} from 'fusion-plugin-universal-events';
-import {FetchToken} from 'fusion-tokens';
-import Redux, {ReduxToken, ReducerToken} from 'fusion-plugin-react-redux';
-
-app.register(UniversalEventsToken, UniversalEvents);
-__NODE__
- ? app.register(RPCHandlersToken, handlers);
- : app.register(FetchToken, fetch);
-```
-
-##### Required dependencies
-
-Name | Type | Description
--|-|-
-`UniversalEventsToken` | `UniversalEvents` | An event emitter plugin, such as the one provided by [`fusion-plugin-universal-events`](https://github.com/fusionjs/fusion-plugin-universal-events).
-`RPCHandlersToken` | `Object<(...args: any) => Promise>` | A map of server-side RPC method implementations. Server-only.
-`FetchToken` | `(url: string, options: Object) => Promise` | A [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) implementation. Browser-only.
-
-#### `withRPCRedux`
-
-```js
-import {withRPCRedux} from 'fusion-plugin-rpc-redux-react';
-const NewComponent = withRPCRedux('rpcId', {
- propName: '', // optional, defaults to rpcId
- mapStateToParams: (state) => ({}), // optional
- transformParams(params) => ({}), // optional
-})(Component)
-```
-
-#### `withRPCReactor`
-```js
-import {withRPCReactor} from 'fusion-plugin-rpc-redux-react';
-const NewComponent = withRPCReactor('rpcId', {
- start: (state, action) => newState, // optional
- success: (state, action) => newState, // optional
- failure: (state, action) => newState, // optional
-},
-{
- propName: '', // optional, defaults to rpcId
- mapStateToParams: (state) => ({}), // optional
- transformParams(params) => ({}), // optional
-})(Component);
-```
-
-### Testing
-
-The package also exports a mock rpc plugin which can be useful for testing. For example:
-
-```js
-import {mock as MockRPC} from 'fusion-plugin-rpc-redux-react';
-app.plugin(mock, {
- handlers: {
- getUser: (args) => {
- return {
- mock: 'data',
- }
- }
- }
-});
-```