Skip to content

Commit

Permalink
Merge 484d923 into 5e2fd2b
Browse files Browse the repository at this point in the history
  • Loading branch information
zemccartney committed Jun 17, 2020
2 parents 5e2fd2b + 484d923 commit cd8c1da
Show file tree
Hide file tree
Showing 7 changed files with 390 additions and 10 deletions.
90 changes: 90 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,93 @@ The `indexes` branch keeps a dictionary of indexes to store the status and resul
Indexing can be skipped by configuring `shouldIndex` to `false` or a function returning `true` or `false` given the index name. Indexes are initialized in the store lazily, i.e. when they are first seen on an action's `meta.index` property.

Typically `entities` and `indexes` work in tandem to keep track of normalized results from an external data-source while keeping them properly normalized.

## React Bindings

#### `<Provider middleEnd={app} />`

React Context Provider component that handles providing the passed middle-end to any nested Context consumers.


It requires the following prop:

- `middleEnd` - A composed application that is set as the context value. The app must be initialized; the component throws otherwise.

```js
const StrangeMiddleEnd = require('strange-middle-end');

// const config = ... standard middle-end config e.g. input to create method

function App ({ props }) {

const m = MiddleEnd.create(config).initialize();

return (
<MiddleEnd.Provider middleEnd={m}>
{/*
Counter may now consume middleEnd context (see useMiddleEnd hook below)
*/}
<Counter />
</MiddleEnd.Provider>
)
}
```

#### `useMiddleEnd()`

Hook that returns the current middle-end as contextualized by the nearest parent `Provider`.
Follows the same rendering logic as [React's built-in `useContext`](https://reactjs.org/docs/hooks-reference.html#usecontext).

```js
function Counter ({ props }) {

const m = useMiddleEnd();

return (
<div>
<button onClick={() => m.dispatch.counter.increment()}>Increment</button>
</div>
)
}
```


If we want to subscribe to and rerender on the state changes dispatched by our button,
we can lean on react-redux, specifically its `useSelector` hook.


```js
const ReactRedux = require('react-redux');
const StrangeMiddleEnd = require('strange-middle-end');

function App ({ props }) {

const m = MiddleEnd.create(config).initialize();

return (
<MiddleEnd.Provider middleEnd={m}>
<ReactRedux.Provider store={m.store}>
<Counter />
</ReactRedux.Provider>
</MiddleEnd.Provider>
)
}

// Then back in our Counter component

const { useSelector } = require('react-redux');

function Counter ({ props }) {

const m = useMiddleEnd();
// Subscribe our selector to changes in our store
const count = useSelector(m.selectors.counter.get);

return (
<div>
<p>The count is {count}</p>
<button onClick={() => m.dispatch.counter.increment()}>Increment</button>
</div>
)
}
```
5 changes: 5 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const Core = require('./core');
const Actions = require('./actions');
const Types = require('./types');
const Reducers = require('./reducers');
const ReactBindings = require('./react');

exports.create = Core.create;

Expand All @@ -28,3 +29,7 @@ exports.isTypeFail = Types.isTypeFail;
exports.createReducer = Reducers.createReducer;

exports.createEntityReducer = Reducers.createEntityReducer;

exports.Provider = ReactBindings.Provider;

exports.useMiddleEnd = ReactBindings.useMiddleEnd;
32 changes: 32 additions & 0 deletions lib/react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';

const React = require('react');

const Context = React.createContext();

Context.displayName = 'StrangeMiddleEnd';

exports.Provider = function Provider({ middleEnd, children }) {

if (!middleEnd || !middleEnd.initialized) {
throw new Error(
'StrangeMiddleEnd.Provider received an unitialized middle-end. Please pass an initialized middle-end.'
);
}

return React.createElement(Context.Provider, {
value: middleEnd
}, children);
};

exports.useMiddleEnd = function useMiddleEnd() {

const m = React.useContext(Context);
if (!m) {
throw new Error(
'No middle-end found. Make sure this component is wrapped in strange-middle-end\'s <Provider>.'
);
}

return m;
};
20 changes: 12 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"scripts": {
"build": "npm run clean && rollup -c",
"clean": "rimraf dist",
"test": "lab -a @hapi/code -t 100 -L",
"lint": "lab -dL",
"test": "lab -a @hapi/code -t 100 -L -I 'regeneratorRuntime'",
"lint": "lab -dL -I 'regeneratorRuntime'",
"coveralls": "lab -r lcov | coveralls"
},
"repository": {
Expand All @@ -37,26 +37,30 @@
"redux": ">=3 <5",
"redux-thunk": "2.x.x",
"immer": ">=1 <7",
"normalizr": "3.x.x"
"normalizr": "3.x.x",
"react": ">=16.8.x <17"
},
"devDependencies": {
"@babel/core": "7.x.x",
"@babel/preset-env": "7.x.x",
"@hapi/code": "8.x.x",
"@hapi/lab": "22.x.x",
"@rollup/plugin-node-resolve": "7.x.x",
"@testing-library/react-hooks": "3.x.x",
"coveralls": "3.x.x",
"immer": "6.x.x",
"normalizr": "3.x.x",
"npm-run-all": "4.x.x",
"react": "^16.8.x",
"react-test-renderer": "^16.8.x",
"redux": "4.x.x",
"redux-thunk": "2.x.x",
"rimraf": "3.x.x",
"rollup": "2.x.x",
"rollup-plugin-babel": "4.x.x",
"rollup-plugin-cjs-es": "1.x.x",
"rollup-plugin-filesize": "7.x.x",
"rollup-plugin-peer-deps-external": "2.x.x",
"rollup-plugin-terser": "5.x.x",
"immer": "6.x.x",
"normalizr": "3.x.x",
"npm-run-all": "4.x.x",
"rimraf": "3.x.x"
"rollup-plugin-terser": "5.x.x"
}
}
3 changes: 2 additions & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ module.exports = [
immer: 'immer',
normalizr: 'normalizr',
redux: 'Redux',
'redux-thunk': 'ReduxThunk'
'redux-thunk': 'ReduxThunk',
react: 'React'
}
},
plugins: [
Expand Down
4 changes: 3 additions & 1 deletion test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ describe('StrangeMiddleEnd', () => {
'isTypeSuccess',
'isTypeFail',
'createReducer',
'createEntityReducer'
'createEntityReducer',
'useMiddleEnd',
'Provider'
]);
});

Expand Down

0 comments on commit cd8c1da

Please sign in to comment.