Merge pull request #315 from streamich/createReducer

This commit is contained in:
Vadim Dalecky 2019-06-04 10:00:51 -07:00 committed by GitHub
commit c3ecced951
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 112 additions and 0 deletions

View File

@ -90,6 +90,8 @@
"react-hooks-testing-library": "0.4.1",
"react-spring": "6.1.10",
"rebound": "0.1.0",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0",
"rimraf": "2.6.3",
"rxjs": "6.5.2",
"semantic-release": "15.13.12",

View File

@ -0,0 +1,55 @@
import { storiesOf } from '@storybook/react';
import * as React from 'react';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
import { createReducer } from '..';
const useThunkReducer = createReducer(thunk, logger);
// React useReducer lazy initialization example: https://reactjs.org/docs/hooks-reference.html#lazy-initialization
function init(initialCount) {
return { count: initialCount };
}
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
case 'reset':
return init(action.payload);
default:
throw new Error();
}
}
const Demo = ({ initialCount = 1 }) => {
// Action creator to increment count, wait a second and then reset
const addAndReset = React.useCallback(() => {
return dispatch2 => {
dispatch2({ type: 'increment' });
setTimeout(() => {
dispatch2({ type: 'reset', payload: initialCount });
}, 1000);
};
}, [initialCount]);
const [state, dispatch] = useThunkReducer(reducer, initialCount, init);
return (
<div>
<pre>{JSON.stringify(state, null, 2)}</pre>
<button onClick={() => dispatch(addAndReset())}>Add and reset</button>
<button onClick={() => dispatch({ type: 'reset', payload: initialCount })}>Reset</button>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
};
storiesOf('State|createReducer', module)
// .add('Docs', () => <ShowDocs md={require('../../docs/createMemo.md')} />)
.add('Demo', () => <Demo />);

36
src/createReducer.ts Normal file
View File

@ -0,0 +1,36 @@
import { useMemo, useRef, useState } from 'react';
function composeMiddleware(chain) {
return (context, dispatch) => {
return chain.reduceRight((res, middleware) => {
return middleware(context)(res);
}, dispatch);
};
}
const createReducer = (...middlewares) => (reducer, initialState, initializer = value => value) => {
const ref = useRef(initializer(initialState));
const [, setState] = useState(ref.current);
let middlewareDispatch = (_ = {}) => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
);
};
const dispatch = action => {
ref.current = reducer(ref.current, action);
setState(ref.current);
return action;
};
const composedMiddleware = useMemo(() => {
return composeMiddleware(middlewares);
}, middlewares);
const middlewareAPI = {
getState: () => ref.current,
dispatch: (...args) => middlewareDispatch(...args),
};
middlewareDispatch = composedMiddleware(middlewareAPI, dispatch);
return [ref.current, middlewareDispatch];
};
export default createReducer;

View File

@ -1,4 +1,5 @@
import createMemo from './createMemo';
import createReducer from './createReducer';
import useAsync from './useAsync';
import useAsyncFn from './useAsyncFn';
import useAsyncRetry from './useAsyncRetry';
@ -73,6 +74,7 @@ import useWindowSize from './useWindowSize';
export {
createMemo,
createReducer,
useAsync,
useAsyncFn,
useAsyncRetry,

View File

@ -5267,6 +5267,11 @@ dedent@^0.7.0:
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=
deep-diff@^0.3.5:
version "0.3.8"
resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84"
integrity sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ=
deep-extend@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
@ -11894,6 +11899,18 @@ redeyed@~2.1.0:
dependencies:
esprima "~4.0.0"
redux-logger@^3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-3.0.6.tgz#f7555966f3098f3c88604c449cf0baf5778274bf"
integrity sha1-91VZZvMJjzyIYExEnPC69XeCdL8=
dependencies:
deep-diff "^0.3.5"
redux-thunk@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
refractor@^2.4.1:
version "2.7.0"
resolved "https://registry.yarnpkg.com/refractor/-/refractor-2.7.0.tgz#3ed9a96a619e75326a429e644241dea51be070a3"