UNPKG

3.59 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _keys = require('babel-runtime/core-js/object/keys');
8
9var _keys2 = _interopRequireDefault(_keys);
10
11var _objectAssign = require('object-assign');
12
13var _objectAssign2 = _interopRequireDefault(_objectAssign);
14
15function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
17// Private action type for controlled-store
18var 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};
37exports.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