1 | ;
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 |
|
7 | var _keys = require('babel-runtime/core-js/object/keys');
|
8 |
|
9 | var _keys2 = _interopRequireDefault(_keys);
|
10 |
|
11 | var _objectAssign = require('object-assign');
|
12 |
|
13 | var _objectAssign2 = _interopRequireDefault(_objectAssign);
|
14 |
|
15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
16 |
|
17 | // Private action type for controlled-store
|
18 | var ActionTypes = {
|
19 | UPDATE: '@@controlled/UPDATE'
|
20 |
|
21 | /**
|
22 | * A Redux store enhancer that allows a redux app to operate as a controlled
|
23 | * component, selectively moving state out of the app and into a container.
|
24 | *
|
25 | * Enhances the store with an additional method `controlledUpdate()` that will
|
26 | * override the redux store state. Any keys on the state object passed to
|
27 | * `controlledUpdate()` will be "locked" in that any actions in the app will no
|
28 | * longer directly update that part of the state, but instead call the `onChange`
|
29 | * function passed to the constructor, with the state key that has been updated
|
30 | * and the new value.
|
31 | *
|
32 | * @param {Function} onChange
|
33 | * @param {Object} stateOverride
|
34 | * @return {Function} Redux Store Enhancer
|
35 | */
|
36 | };
|
37 | exports.default = function (onChange) {
|
38 | var initialStateOverride = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
39 | return function (createStore) {
|
40 | // These properties of the app state are now controlled
|
41 | var controlledProps = (0, _keys2.default)(initialStateOverride);
|
42 |
|
43 | return function (reducer, initialState, enhancer) {
|
44 | initialState = (0, _objectAssign2.default)({}, initialState, initialStateOverride);
|
45 | // Create the store with an enhanced reducer
|
46 | var store = createStore(controlledReducer, initialState, enhancer);
|
47 |
|
48 | // Enhance the store with an additional method `controlledUpdate()`
|
49 | return (0, _objectAssign2.default)({}, store, {
|
50 | controlledUpdate: controlledUpdate
|
51 | });
|
52 |
|
53 | function controlledReducer(state, action) {
|
54 | // Controlled updates skip app reducers and override the state
|
55 | if (action.type === ActionTypes.UPDATE) {
|
56 | return (0, _objectAssign2.default)({}, state, action.payload);
|
57 | }
|
58 | var hasChanged = false;
|
59 | var newState = reducer(state, action);
|
60 | (0, _keys2.default)(newState).forEach(function (key) {
|
61 | if (newState[key] === state[key]) return;
|
62 | var value = newState[key];
|
63 | process.nextTick(function () {
|
64 | return onChange(key, value);
|
65 | });
|
66 | if (controlledProps.indexOf(key) > -1) {
|
67 | // If any controlled props of the state are updated, we hide the
|
68 | // initial change in state from the redux store and instead
|
69 | // call the `onChange` function with the key that has been updated
|
70 | // and the new value. Needs to run on nextTick to avoid `controlledUpdate()`
|
71 | // being called in the same tick and resulting in a `store.dispatch()`
|
72 | // inside this reducer.
|
73 | newState[key] = state[key];
|
74 | } else {
|
75 | // Unless an uncontrolled prop has been changed, we'll just return the existing state
|
76 | hasChanged = true;
|
77 | }
|
78 | });
|
79 | return hasChanged ? newState : state;
|
80 | }
|
81 |
|
82 | function controlledUpdate(stateOverride) {
|
83 | controlledProps = (0, _keys2.default)(stateOverride);
|
84 | store.dispatch({
|
85 | type: ActionTypes.UPDATE,
|
86 | payload: stateOverride
|
87 | });
|
88 | }
|
89 | };
|
90 | };
|
91 | };
|
92 | //# sourceMappingURL=controlled_store.js.map |
\ | No newline at end of file |