Comparing version 1.0.0-rc to 1.0.0
144
CHANGELOG.md
@@ -6,4 +6,78 @@ # Change log | ||
## [unreleased] | ||
## [1.0.0](https://github.com/rackt/redux/compare/v1.0.0-rc...v1.0.0) - 2015/08/14 | ||
### Breaking Changes | ||
* If `dispatch` is attempted while reducer is executing, an error is thrown. Note that you can dispatch from lifecycle hooks just fine. It's only reducers that are not allowed to dispatch. (https://github.com/rackt/redux/issues/368) | ||
### New Home | ||
We moved under [rackt](https://github.com/rackt) Github org. This won't affect you, but the new official URL is https://github.com/rackt/redux. We did this because we share values, and we want to collaborate on creating better tools, libraries, documentation, and examples. Redux stays independent of React, but we will work closely with React Router community to figure out a better integration. | ||
### Docs! | ||
[We have real docs now.](http://rackt.github.io/redux/) There are a few missing pieces, but it's a terrific effort, so thanks to everybody who contributed in the past month to get this shipped. Thanks to [Gitbook](https://github.com/GitbookIO/gitbook) for providing great tooling, too. | ||
### Examples! | ||
There's been no shortage of great examples in [Awesome Redux](https://github.com/xgrommx/awesome-redux), but we're shipping two new built-in examples in 1.0. One of them is a [very simple async application](https://github.com/rackt/redux/tree/master/examples/async). Creating it is covered in [async tutorial](http://rackt.github.io/redux/docs/advanced/AsyncActions.html). Another example we ship is a [“real-world” example](https://github.com/rackt/redux/tree/master/examples/real-world). It's a port of somewhat well-known [flux-react-router-example](https://github.com/gaearon/flux-react-router-example) to Redux, and shows advanced techniques such as caching, data normalization, custom API middleware, and pagination. Hopefully this example will help answer some commonly asked questions. | ||
### Other Improvements | ||
* Unsubscribing during a dispatch is now fixed: https://github.com/rackt/redux/pull/462 | ||
* `bindActionCreators` now can also accept a function as the first argument: https://github.com/rackt/redux/pull/352 | ||
* Dispatching from iframe now works: https://github.com/rackt/redux/issues/304 | ||
* Symbols can be used as action types: https://github.com/rackt/redux/pull/295 (Note: we don't recommend you to do this, because they're not serializable, so you can't record/replay user sessions.) | ||
## [1.0.0-rc](https://github.com/rackt/redux/compare/v1.0.0-alpha...v1.0.0-rc) - 2015/07/13 | ||
### Big Changes | ||
* React-specific code has been moved to [react-redux](https://github.com/rackt/react-redux) and will be versioned separately | ||
* `createStore` no longer implicitly combines reducers | ||
* All middleware is now “smart” middleware | ||
* `createStore` no longer accepts middleware | ||
* The thunk middleware is no longer included by default | ||
### Correctness Changes | ||
* `combineReducers` now throws if you return `undefined` state | ||
* `combineReducers` throws if you have no `default` case | ||
* (React) Components now update correctly in response to the actions fired in `componentDidMount` | ||
* Dispatch from the middleware sends the dispatch through the whole middleware chain | ||
**Read the [detailed upgrade notes on the release page.](https://github.com/rackt/redux/releases/tag/v1.0.0-rc)** | ||
## [1.0.0-alpha](https://github.com/rackt/redux/compare/v0.12.0...v1.0.0-alpha) - 2015/06/30 | ||
### Naming | ||
* “Stateless Stores” are now called reducers. (https://github.com/rackt/redux/issues/137#issuecomment-114178411) | ||
* The “Redux instance” is now called “The Store”. (https://github.com/rackt/redux/issues/137#issuecomment-113252359) | ||
* The dispatcher is removed completely. (https://github.com/rackt/redux/pull/166#issue-90113962) | ||
### API changes | ||
* <s>`composeStores`</s> is now `composeReducers`. | ||
* <s>`createDispatcher`</s> is gone. | ||
* <s>`createRedux`</s> is now `createStore`. | ||
* `<Provider>` now accepts `store` prop instead of <s>`redux`</s>. | ||
* The new `createStore` signature is `createStore(reducer: Function | Object, initialState: any, middlewares: Array | ({ getState, dispatch }) => Array)`. | ||
* If the first argument to `createStore` is an object, `composeReducers` is automatically applied to it. | ||
* The “smart” middleware signature changed. It now accepts an object instead of a single `getState` function. The `dispatch` function lets you “recurse” the middleware chain and is useful for async: #113 (comment). | ||
### Correctness changes | ||
* The `dispatch` provided by the default thunk middleware now walks the whole middleware chain. | ||
* It is enforced now that raw Actions at the end of the middleware chain have to be plain objects. | ||
* Nested dispatches are now handled gracefully. (#110, #119) | ||
### Internal changes | ||
* The object in React context is renamed from <s>`redux`</s> to `store`. | ||
* Some tests are rewritten for clarity, focus and edge cases. | ||
* Redux in examples is now aliased to the source code for easier work on master. | ||
**Read the [detailed upgrade notes on the release page.](https://github.com/rackt/redux/releases/tag/v1.0.0-alpha)** | ||
## [0.12.0] - 2015/06/19 | ||
@@ -47,4 +121,4 @@ No breaking changes this time. | ||
* `Connector` now throws if `select` returns something other than a plain object (https://github.com/gaearon/redux/pull/85) | ||
* The custom dispatcher API is tweaked so `setState` now returns the state that was actually set. This makes custom dispatchers more composable. (https://github.com/gaearon/redux/pull/77) | ||
* `Connector` now throws if `select` returns something other than a plain object (https://github.com/rackt/redux/pull/85) | ||
* The custom dispatcher API is tweaked so `setState` now returns the state that was actually set. This makes custom dispatchers more composable. (https://github.com/rackt/redux/pull/77) | ||
@@ -56,11 +130,11 @@ Happy reducing! | ||
Redux 1.0 is within striking distance! Can you believe how quickly Redux has matured? @gaearon made the first commit only [14 days ago](https://github.com/gaearon/redux/commit/8bc14659780c044baac1432845fe1e4ca5123a8d). | ||
Redux 1.0 is within striking distance! Can you believe how quickly Redux has matured? @rackt made the first commit only [14 days ago](https://github.com/rackt/redux/commit/8bc14659780c044baac1432845fe1e4ca5123a8d). | ||
The 0.10 release is a follow-up to 0.9, with a focus on what we're calling (at least for now) **middleware**. | ||
You can read all about middleware [here](https://github.com/gaearon/redux/blob/master/docs/middleware.md). We plan to release some official middleware soon, but of course we'd also love to see middleware created by the community. | ||
You can read all about middleware [here](https://github.com/rackt/redux/blob/master/docs/middleware.md). We plan to release some official middleware soon, but of course we'd also love to see middleware created by the community. | ||
### Breaking changes | ||
Just a small one: Redux includes a feature that enables you to return a function from an action creator to perform asynchronous dispatches. The function receives a callback and `getState()` as parameters. This has behavior has been re-implemented as middleware and moved into a separate module called [`thunkMiddleware()`](https://github.com/gaearon/redux/blob/master/src/middleware/thunk.js). It is included automatically when using the `createRedux(stores)` shortcut, but not when using `createDispatcher()`. | ||
Just a small one: Redux includes a feature that enables you to return a function from an action creator to perform asynchronous dispatches. The function receives a callback and `getState()` as parameters. This has behavior has been re-implemented as middleware and moved into a separate module called [`thunkMiddleware()`](https://github.com/rackt/redux/blob/master/src/middleware/thunk.js). It is included automatically when using the `createRedux(stores)` shortcut, but not when using `createDispatcher()`. | ||
@@ -196,3 +270,3 @@ ### Tests | ||
Read the discussion: https://github.com/gaearon/redux/pull/46 | ||
Read the discussion: https://github.com/rackt/redux/pull/46 | ||
@@ -251,3 +325,3 @@ ## [0.7.0] - 2015/06/06 | ||
## [0.5.0] - 2015/06/03 | ||
* Store function names are no longer significant, but you have to pass an object with all your Stores to the `root` (or `Root`). Fixes https://github.com/gaearon/redux/issues/16 | ||
* Store function names are no longer significant, but you have to pass an object with all your Stores to the `root` (or `Root`). Fixes https://github.com/rackt/redux/issues/16 | ||
@@ -273,6 +347,6 @@ ```js | ||
## [0.4.0] - 2015/06/03 | ||
* Bring decorators back, now on top of the lower-level container components (https://github.com/gaearon/redux/pull/15, thanks Florent) | ||
* Bring decorators back, now on top of the lower-level container components (https://github.com/rackt/redux/pull/15, thanks Florent) | ||
* Require `stores` passed to `Container` to be an array | ||
* Fix build on Windows (https://github.com/gaearon/redux/pull/11, thanks Mike) | ||
* Reduce context footprint (https://github.com/gaearon/redux/pull/12, thanks Florent again!) | ||
* Fix build on Windows (https://github.com/rackt/redux/pull/11, thanks Mike) | ||
* Reduce context footprint (https://github.com/rackt/redux/pull/12, thanks Florent again!) | ||
@@ -286,4 +360,4 @@ ## [0.3.1] - 2015/06/03 | ||
* **No more strings,** now using module bindings for injecting stores and actions | ||
* Only use decorator for top-level component, keep dumb components pure and testable (https://github.com/gaearon/redux/issues/5) | ||
* Remove transaction logic (will be re-implemented on top of https://github.com/gaearon/redux/issues/6) | ||
* Only use decorator for top-level component, keep dumb components pure and testable (https://github.com/rackt/redux/issues/5) | ||
* Remove transaction logic (will be re-implemented on top of https://github.com/rackt/redux/issues/6) | ||
@@ -325,25 +399,25 @@ ```js | ||
* Initial public release. | ||
See examples in [README](https://github.com/gaearon/redux/blob/master/README.md) and the | ||
[examples](https://github.com/gaearon/redux/tree/master/examples) folder. | ||
See examples in [README](https://github.com/rackt/redux/blob/master/README.md) and the | ||
[examples](https://github.com/rackt/redux/tree/master/examples) folder. | ||
Alpha quality :-) | ||
[unreleased]: https://github.com/gaearon/redux/compare/v0.12.0...HEAD | ||
[0.12.0]: https://github.com/gaearon/redux/compare/v0.11.1...v0.12.0 | ||
[0.11.1]: https://github.com/gaearon/redux/compare/v0.11.0...v0.11.1 | ||
[0.11.0]: https://github.com/gaearon/redux/compare/v0.10.1...v0.11.0 | ||
[0.10.1]: https://github.com/gaearon/redux/compare/v0.10.0...v0.10.1 | ||
[0.10.0]: https://github.com/gaearon/redux/compare/v0.9.0...v0.10.0 | ||
[0.9.0]: https://github.com/gaearon/redux/compare/v0.8.1...v0.9.0 | ||
[0.8.1]: https://github.com/gaearon/redux/compare/v0.8.0...v0.8.1 | ||
[0.8.0]: https://github.com/gaearon/redux/compare/v0.7.0...v0.8.0 | ||
[0.7.0]: https://github.com/gaearon/redux/compare/v0.6.2...v0.7.0 | ||
[0.6.2]: https://github.com/gaearon/redux/compare/v0.6.1...v0.6.2 | ||
[0.6.1]: https://github.com/gaearon/redux/compare/v0.6.0...v0.6.1 | ||
[0.6.0]: https://github.com/gaearon/redux/compare/v0.5.1...v0.6.0 | ||
[0.5.1]: https://github.com/gaearon/redux/compare/v0.5.0...v0.5.1 | ||
[0.5.0]: https://github.com/gaearon/redux/compare/v0.4.0...v0.5.0 | ||
[0.4.0]: https://github.com/gaearon/redux/compare/v0.3.1...v0.4.0 | ||
[0.3.1]: https://github.com/gaearon/redux/compare/v0.3.0...v0.3.1 | ||
[0.3.0]: https://github.com/gaearon/redux/compare/v0.2.2...v0.3.0 | ||
[0.2.2]: https://github.com/gaearon/redux/compare/v0.2.1...v0.2.2 | ||
[0.2.1]: https://github.com/gaearon/redux/compare/v0.2.0...v0.2.1 | ||
[unreleased]: https://github.com/rackt/redux/compare/v0.12.0...HEAD | ||
[0.12.0]: https://github.com/rackt/redux/compare/v0.11.1...v0.12.0 | ||
[0.11.1]: https://github.com/rackt/redux/compare/v0.11.0...v0.11.1 | ||
[0.11.0]: https://github.com/rackt/redux/compare/v0.10.1...v0.11.0 | ||
[0.10.1]: https://github.com/rackt/redux/compare/v0.10.0...v0.10.1 | ||
[0.10.0]: https://github.com/rackt/redux/compare/v0.9.0...v0.10.0 | ||
[0.9.0]: https://github.com/rackt/redux/compare/v0.8.1...v0.9.0 | ||
[0.8.1]: https://github.com/rackt/redux/compare/v0.8.0...v0.8.1 | ||
[0.8.0]: https://github.com/rackt/redux/compare/v0.7.0...v0.8.0 | ||
[0.7.0]: https://github.com/rackt/redux/compare/v0.6.2...v0.7.0 | ||
[0.6.2]: https://github.com/rackt/redux/compare/v0.6.1...v0.6.2 | ||
[0.6.1]: https://github.com/rackt/redux/compare/v0.6.0...v0.6.1 | ||
[0.6.0]: https://github.com/rackt/redux/compare/v0.5.1...v0.6.0 | ||
[0.5.1]: https://github.com/rackt/redux/compare/v0.5.0...v0.5.1 | ||
[0.5.0]: https://github.com/rackt/redux/compare/v0.4.0...v0.5.0 | ||
[0.4.0]: https://github.com/rackt/redux/compare/v0.3.1...v0.4.0 | ||
[0.3.1]: https://github.com/rackt/redux/compare/v0.3.0...v0.3.1 | ||
[0.3.0]: https://github.com/rackt/redux/compare/v0.2.2...v0.3.0 | ||
[0.2.2]: https://github.com/rackt/redux/compare/v0.2.1...v0.2.2 | ||
[0.2.1]: https://github.com/rackt/redux/compare/v0.2.0...v0.2.1 |
@@ -57,3 +57,2 @@ (function webpackUniversalModuleDefinition(root, factory) { | ||
// Core | ||
'use strict'; | ||
@@ -65,61 +64,87 @@ | ||
var _createStore = __webpack_require__(6); | ||
var _createStore = __webpack_require__(2); | ||
var _createStore2 = _interopRequireDefault(_createStore); | ||
// Utilities | ||
var _utilsCombineReducers = __webpack_require__(8); | ||
var _utilsCompose = __webpack_require__(1); | ||
var _utilsCompose2 = _interopRequireDefault(_utilsCompose); | ||
var _utilsCombineReducers = __webpack_require__(9); | ||
var _utilsCombineReducers2 = _interopRequireDefault(_utilsCombineReducers); | ||
var _utilsBindActionCreators = __webpack_require__(8); | ||
var _utilsBindActionCreators = __webpack_require__(7); | ||
var _utilsBindActionCreators2 = _interopRequireDefault(_utilsBindActionCreators); | ||
var _utilsApplyMiddleware = __webpack_require__(7); | ||
var _utilsApplyMiddleware = __webpack_require__(6); | ||
var _utilsApplyMiddleware2 = _interopRequireDefault(_utilsApplyMiddleware); | ||
var _utilsComposeMiddleware = __webpack_require__(3); | ||
var _utilsCompose = __webpack_require__(3); | ||
var _utilsComposeMiddleware2 = _interopRequireDefault(_utilsComposeMiddleware); | ||
var _utilsCompose2 = _interopRequireDefault(_utilsCompose); | ||
exports.createStore = _createStore2['default']; | ||
exports.compose = _utilsCompose2['default']; | ||
exports.combineReducers = _utilsCombineReducers2['default']; | ||
exports.bindActionCreators = _utilsBindActionCreators2['default']; | ||
exports.applyMiddleware = _utilsApplyMiddleware2['default']; | ||
exports.composeMiddleware = _utilsComposeMiddleware2['default']; | ||
exports.compose = _utilsCompose2['default']; | ||
/***/ }, | ||
/* 1 */ | ||
/***/ function(module, exports) { | ||
/***/ function(module, exports, __webpack_require__) { | ||
/** | ||
* Composes functions from left to right | ||
* @param {...Function} funcs - Functions to compose | ||
* @return {Function} | ||
* Copyright 2013-2015, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* @providesModule invariant | ||
*/ | ||
"use strict"; | ||
exports.__esModule = true; | ||
exports["default"] = compose; | ||
'use strict'; | ||
function compose() { | ||
for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) { | ||
funcs[_key] = arguments[_key]; | ||
/** | ||
* Use invariant() to assert state which your program assumes to be true. | ||
* | ||
* Provide sprintf-style format (only %s is supported) and arguments | ||
* to provide information about what broke and what you were | ||
* expecting. | ||
* | ||
* The invariant message will be stripped in production, but the invariant | ||
* will remain to ensure logic does not differ in production. | ||
*/ | ||
var invariant = function(condition, format, a, b, c, d, e, f) { | ||
if (true) { | ||
if (format === undefined) { | ||
throw new Error('invariant requires an error message argument'); | ||
} | ||
} | ||
return funcs.reduceRight(function (composed, f) { | ||
return f(composed); | ||
}); | ||
} | ||
if (!condition) { | ||
var error; | ||
if (format === undefined) { | ||
error = new Error( | ||
'Minified exception occurred; use the non-minified dev environment ' + | ||
'for the full error message and additional helpful warnings.' | ||
); | ||
} else { | ||
var args = [a, b, c, d, e, f]; | ||
var argIndex = 0; | ||
error = new Error( | ||
'Invariant Violation: ' + | ||
format.replace(/%s/g, function() { return args[argIndex++]; }) | ||
); | ||
} | ||
module.exports = exports["default"]; | ||
error.framesToPop = 1; // we don't care about invariant's own frame | ||
throw error; | ||
} | ||
}; | ||
module.exports = invariant; | ||
/***/ }, | ||
@@ -132,18 +157,20 @@ /* 2 */ | ||
exports.__esModule = true; | ||
exports['default'] = createStore; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
var _invariant = __webpack_require__(1); | ||
var _invariant = __webpack_require__(5); | ||
var _invariant2 = _interopRequireDefault(_invariant); | ||
var _utilsIsPlainObject = __webpack_require__(10); | ||
var _utilsIsPlainObject = __webpack_require__(4); | ||
var _utilsIsPlainObject2 = _interopRequireDefault(_utilsIsPlainObject); | ||
// Don't ever try to handle these action types in your code. They are private. | ||
// For any unknown actions, you must return the current state. | ||
// If the current state is undefined, you must return the initial state. | ||
/** | ||
* These are private action types reserved by Redux. | ||
* For any unknown actions, you must return the current state. | ||
* If the current state is undefined, you must return the initial state. | ||
* Do not reference these action types directly in your code. | ||
*/ | ||
var ActionTypes = { | ||
@@ -154,88 +181,199 @@ INIT: '@@redux/INIT' | ||
exports.ActionTypes = ActionTypes; | ||
/** | ||
* Creates a Redux store that holds the state tree. | ||
* The only way to change the data in the store is to call `dispatch()` on it. | ||
* | ||
* There should only be a single store in your app. To specify how different | ||
* parts of the state tree respond to actions, you may combine several reducers | ||
* into a single reducer function by using `combineReducers`. | ||
* | ||
* @param {Function} reducer A function that returns the next state tree, given | ||
* the current state tree and the action to handle. | ||
* | ||
* @param {any} [initialState] The initial state. You may optionally specify it | ||
* to hydrate the state from the server in universal apps, or to restore a | ||
* previously serialized user session. | ||
* If you use `combineReducers` to produce the root reducer function, this must be | ||
* an object with the same shape as `combineReducers` keys. | ||
* | ||
* @returns {Store} A Redux store that lets you read the state, dispatch actions | ||
* and subscribe to changes. | ||
*/ | ||
var Store = (function () { | ||
function Store(reducer, initialState) { | ||
_classCallCheck(this, Store); | ||
function createStore(reducer, initialState) { | ||
_invariant2['default'](typeof reducer === 'function', 'Expected the reducer to be a function.'); | ||
_invariant2['default'](typeof reducer === 'function', 'Expected the reducer to be a function.'); | ||
var currentReducer = reducer; | ||
var currentState = initialState; | ||
var listeners = []; | ||
var isDispatching = false; | ||
this.state = initialState; | ||
this.listeners = []; | ||
this.replaceReducer(reducer); | ||
/** | ||
* Reads the state tree managed by the store. | ||
* | ||
* @returns {any} The current state tree of your application. | ||
*/ | ||
function getState() { | ||
return currentState; | ||
} | ||
Store.prototype.getReducer = function getReducer() { | ||
return this.reducer; | ||
}; | ||
/** | ||
* Adds a change listener. It will be called any time an action is dispatched, | ||
* and some part of the state tree may potentially have changed. You may then | ||
* call `getState()` to read the current state tree inside the callback. | ||
* | ||
* @param {Function} listener A callback to be invoked on every dispatch. | ||
* @returns {Function} A function to remove this change listener. | ||
*/ | ||
function subscribe(listener) { | ||
listeners.push(listener); | ||
Store.prototype.replaceReducer = function replaceReducer(nextReducer) { | ||
this.reducer = nextReducer; | ||
this.dispatch({ type: ActionTypes.INIT }); | ||
}; | ||
return function unsubscribe() { | ||
var index = listeners.indexOf(listener); | ||
listeners.splice(index, 1); | ||
}; | ||
} | ||
Store.prototype.dispatch = function dispatch(action) { | ||
/** | ||
* Dispatches an action. It is the only way to trigger a state change. | ||
* | ||
* The `reducer` function, used to create the store, will be called with the | ||
* current state tree and the given `action`. Its return value will | ||
* be considered the **next** state of the tree, and the change listeners | ||
* will be notified. | ||
* | ||
* The base implementation only supports plain object actions. If you want to | ||
* dispatch a Promise, an Observable, a thunk, or something else, you need to | ||
* wrap your store creating function into the corresponding middleware. For | ||
* example, see the documentation for the `redux-thunk` package. Even the | ||
* middleware will eventually dispatch plain object actions using this method. | ||
* | ||
* @param {Object} action A plain object representing “what changed”. It is | ||
* a good idea to keep actions serializable so you can record and replay user | ||
* sessions, or use the time travelling `redux-devtools`. | ||
* | ||
* @returns {Object} For convenience, the same action object you dispatched. | ||
* | ||
* Note that, if you use a custom middleware, it may wrap `dispatch()` to | ||
* return something else (for example, a Promise you can await). | ||
*/ | ||
function dispatch(action) { | ||
_invariant2['default'](_utilsIsPlainObject2['default'](action), 'Actions must be plain objects. Use custom middleware for async actions.'); | ||
var reducer = this.reducer; | ||
_invariant2['default'](isDispatching === false, 'Reducers may not dispatch actions.'); | ||
this.state = reducer(this.state, action); | ||
this.listeners.forEach(function (listener) { | ||
try { | ||
isDispatching = true; | ||
currentState = currentReducer(currentState, action); | ||
} finally { | ||
isDispatching = false; | ||
} | ||
listeners.slice().forEach(function (listener) { | ||
return listener(); | ||
}); | ||
return action; | ||
}; | ||
} | ||
Store.prototype.getState = function getState() { | ||
return this.state; | ||
}; | ||
/** | ||
* Returns the reducer currently used by the store to calculate the state. | ||
* | ||
* It is likely that you will only need this function if you implement a hot | ||
* reloading mechanism for Redux. | ||
* | ||
* @returns {Function} The reducer used by the current store. | ||
*/ | ||
function getReducer() { | ||
return currentReducer; | ||
} | ||
Store.prototype.subscribe = function subscribe(listener) { | ||
var listeners = this.listeners; | ||
/** | ||
* Replaces the reducer currently used by the store to calculate the state. | ||
* | ||
* You might need this if your app implements code splitting and you want to | ||
* load some of the reducers dynamically. You might also need this if you | ||
* implement a hot reloading mechanism for Redux. | ||
* | ||
* @param {Function} nextReducer The reducer for the store to use instead. | ||
* @returns {void} | ||
*/ | ||
function replaceReducer(nextReducer) { | ||
currentReducer = nextReducer; | ||
dispatch({ type: ActionTypes.INIT }); | ||
} | ||
listeners.push(listener); | ||
// When a store is created, an "INIT" action is dispatched so that every | ||
// reducer returns their initial state. This effectively populates | ||
// the initial state tree. | ||
dispatch({ type: ActionTypes.INIT }); | ||
return function unsubscribe() { | ||
var index = listeners.indexOf(listener); | ||
listeners.splice(index, 1); | ||
}; | ||
return { | ||
dispatch: dispatch, | ||
subscribe: subscribe, | ||
getState: getState, | ||
getReducer: getReducer, | ||
replaceReducer: replaceReducer | ||
}; | ||
} | ||
return Store; | ||
})(); | ||
exports['default'] = Store; | ||
/***/ }, | ||
/* 3 */ | ||
/***/ function(module, exports, __webpack_require__) { | ||
/***/ function(module, exports) { | ||
'use strict'; | ||
/** | ||
* Composes functions from left to right. | ||
* | ||
* @param {...Function} funcs - The functions to compose. Each is expected to | ||
* accept a function as an argument and to return a function. | ||
* @returns {Function} A function obtained by composing functions from left to | ||
* right. | ||
*/ | ||
"use strict"; | ||
exports.__esModule = true; | ||
exports['default'] = composeMiddleware; | ||
exports["default"] = compose; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
function compose() { | ||
for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) { | ||
funcs[_key] = arguments[_key]; | ||
} | ||
var _compose = __webpack_require__(1); | ||
return funcs.reduceRight(function (composed, f) { | ||
return f(composed); | ||
}); | ||
} | ||
var _compose2 = _interopRequireDefault(_compose); | ||
module.exports = exports["default"]; | ||
/***/ }, | ||
/* 4 */ | ||
/***/ function(module, exports) { | ||
'use strict'; | ||
exports.__esModule = true; | ||
exports['default'] = isPlainObject; | ||
var fnToString = function fnToString(fn) { | ||
return Function.prototype.toString.call(fn); | ||
}; | ||
/** | ||
* Compose middleware from left to right | ||
* @param {...Function} middlewares | ||
* @return {Function} | ||
* @param {any} obj The object to inspect. | ||
* @returns {boolean} True if the argument appears to be a plain object. | ||
*/ | ||
function composeMiddleware() { | ||
for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) { | ||
middlewares[_key] = arguments[_key]; | ||
function isPlainObject(obj) { | ||
if (!obj || typeof obj !== 'object') { | ||
return false; | ||
} | ||
return function (methods) { | ||
return function (next) { | ||
return _compose2['default'].apply(undefined, middlewares.map(function (m) { | ||
return m(methods); | ||
}).concat([next])); | ||
}; | ||
}; | ||
var proto = typeof obj.constructor === 'function' ? Object.getPrototypeOf(obj) : Object.prototype; | ||
if (proto === null) { | ||
return true; | ||
} | ||
var constructor = proto.constructor; | ||
return typeof constructor === 'function' && constructor instanceof constructor && fnToString(constructor) === fnToString(Object); | ||
} | ||
@@ -246,5 +384,12 @@ | ||
/***/ }, | ||
/* 4 */ | ||
/* 5 */ | ||
/***/ function(module, exports) { | ||
/** | ||
* Applies a function to every key-value pair inside an object. | ||
* | ||
* @param {Object} obj The source object. | ||
* @param {Function} fn The mapper function taht receives the value and the key. | ||
* @returns {Object} A new object that contains the mapped values for the keys. | ||
*/ | ||
"use strict"; | ||
@@ -265,61 +410,2 @@ | ||
/***/ }, | ||
/* 5 */ | ||
/***/ function(module, exports, __webpack_require__) { | ||
/** | ||
* Copyright 2013-2015, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* @providesModule invariant | ||
*/ | ||
'use strict'; | ||
/** | ||
* Use invariant() to assert state which your program assumes to be true. | ||
* | ||
* Provide sprintf-style format (only %s is supported) and arguments | ||
* to provide information about what broke and what you were | ||
* expecting. | ||
* | ||
* The invariant message will be stripped in production, but the invariant | ||
* will remain to ensure logic does not differ in production. | ||
*/ | ||
var invariant = function(condition, format, a, b, c, d, e, f) { | ||
if ((undefined) !== 'production') { | ||
if (format === undefined) { | ||
throw new Error('invariant requires an error message argument'); | ||
} | ||
} | ||
if (!condition) { | ||
var error; | ||
if (format === undefined) { | ||
error = new Error( | ||
'Minified exception occurred; use the non-minified dev environment ' + | ||
'for the full error message and additional helpful warnings.' | ||
); | ||
} else { | ||
var args = [a, b, c, d, e, f]; | ||
var argIndex = 0; | ||
error = new Error( | ||
'Invariant Violation: ' + | ||
format.replace(/%s/g, function() { return args[argIndex++]; }) | ||
); | ||
} | ||
error.framesToPop = 1; // we don't care about invariant's own frame | ||
throw error; | ||
} | ||
}; | ||
module.exports = invariant; | ||
/***/ }, | ||
/* 6 */ | ||
@@ -331,32 +417,3 @@ /***/ function(module, exports, __webpack_require__) { | ||
exports.__esModule = true; | ||
exports['default'] = createStore; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
var _Store = __webpack_require__(2); | ||
var _Store2 = _interopRequireDefault(_Store); | ||
function createStore(reducer, initialState) { | ||
var store = new _Store2['default'](reducer, initialState); | ||
return { | ||
dispatch: store.dispatch.bind(store), | ||
subscribe: store.subscribe.bind(store), | ||
getState: store.getState.bind(store), | ||
getReducer: store.getReducer.bind(store), | ||
replaceReducer: store.replaceReducer.bind(store) | ||
}; | ||
} | ||
module.exports = exports['default']; | ||
/***/ }, | ||
/* 7 */ | ||
/***/ function(module, exports, __webpack_require__) { | ||
'use strict'; | ||
exports.__esModule = true; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
@@ -368,16 +425,21 @@ | ||
var _compose = __webpack_require__(1); | ||
var _compose = __webpack_require__(3); | ||
var _compose2 = _interopRequireDefault(_compose); | ||
var _composeMiddleware = __webpack_require__(3); | ||
var _composeMiddleware2 = _interopRequireDefault(_composeMiddleware); | ||
/** | ||
* Creates a higher-order store that applies middleware to a store's dispatch. | ||
* Creates a store enhancer that applies middleware to the dispatch method | ||
* of the Redux store. This is handy for a variety of tasks, such as expressing | ||
* asynchronous actions in a concise manner, or logging every action payload. | ||
* | ||
* See `redux-thunk` package as an example of the Redux middleware. | ||
* | ||
* Because middleware is potentially asynchronous, this should be the first | ||
* higher-order store in the composition chain. | ||
* @param {...Function} ...middlewares | ||
* @return {Function} A higher-order store | ||
* store enhancer in the composition chain. | ||
* | ||
* Note that each middleware will be given the `dispatch` and `getState` functions | ||
* as named arguments. | ||
* | ||
* @param {...Function} middlewares The middleware chain to be applied. | ||
* @returns {Function} A store enhancer applying the middleware. | ||
*/ | ||
@@ -391,17 +453,20 @@ | ||
return function (next) { | ||
return function () { | ||
var store = next.apply(undefined, arguments); | ||
var middleware = _composeMiddleware2['default'].apply(undefined, middlewares); | ||
return function (reducer, initialState) { | ||
var store = next(reducer, initialState); | ||
var _dispatch = store.dispatch; | ||
var chain = []; | ||
function dispatch(action) { | ||
var methods = { | ||
dispatch: dispatch, | ||
getState: store.getState | ||
}; | ||
var middlewareAPI = { | ||
getState: store.getState, | ||
dispatch: function dispatch(action) { | ||
return _dispatch(action); | ||
} | ||
}; | ||
chain = middlewares.map(function (middleware) { | ||
return middleware(middlewareAPI); | ||
}); | ||
_dispatch = _compose2['default'].apply(undefined, chain.concat([store.dispatch])); | ||
return _compose2['default'](middleware(methods), store.dispatch)(action); | ||
} | ||
return _extends({}, store, { | ||
dispatch: dispatch | ||
dispatch: _dispatch | ||
}); | ||
@@ -415,3 +480,3 @@ }; | ||
/***/ }, | ||
/* 8 */ | ||
/* 7 */ | ||
/***/ function(module, exports, __webpack_require__) { | ||
@@ -426,11 +491,47 @@ | ||
var _utilsMapValues = __webpack_require__(4); | ||
var _invariant = __webpack_require__(1); | ||
var _invariant2 = _interopRequireDefault(_invariant); | ||
var _utilsMapValues = __webpack_require__(5); | ||
var _utilsMapValues2 = _interopRequireDefault(_utilsMapValues); | ||
function bindActionCreator(actionCreator, dispatch) { | ||
return function () { | ||
return dispatch(actionCreator.apply(undefined, arguments)); | ||
}; | ||
} | ||
/** | ||
* Turns an object whose values are action creators, into an object with the | ||
* same keys, but with every function wrapped into a `dispatch` call so they | ||
* may be invoked directly. This is just a convenience method, as you can call | ||
* `store.dispatch(MyActionCreators.doSomething())` yourself just fine. | ||
* | ||
* For convenience, you can also pass a single function as the first argument, | ||
* and get a function in return. | ||
* | ||
* @param {Function|Object} actionCreators An object whose values are action | ||
* creator functions. One handy way to obtain it is to use ES6 `import * as` | ||
* syntax. You may also pass a single function. | ||
* | ||
* @param {Function} dispatch The `dispatch` function available on your Redux | ||
* store. | ||
* | ||
* @returns {Function|Object} The object mimicking the original object, but with | ||
* every action creator wrapped into the `dispatch` call. If you passed a | ||
* function as `actionCreators`, the return value will also be a single | ||
* function. | ||
*/ | ||
function bindActionCreators(actionCreators, dispatch) { | ||
if (typeof actionCreators === 'function') { | ||
return bindActionCreator(actionCreators, dispatch); | ||
} | ||
_invariant2['default'](typeof actionCreators === 'object' && actionCreators != null, 'bindActionCreators expected an object or a function, instead received %s. ' + 'Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?', typeof actionCreators); | ||
return _utilsMapValues2['default'](actionCreators, function (actionCreator) { | ||
return function () { | ||
return dispatch(actionCreator.apply(undefined, arguments)); | ||
}; | ||
return bindActionCreator(actionCreator, dispatch); | ||
}); | ||
@@ -442,3 +543,3 @@ } | ||
/***/ }, | ||
/* 9 */ | ||
/* 8 */ | ||
/***/ function(module, exports, __webpack_require__) { | ||
@@ -453,19 +554,27 @@ | ||
var _utilsMapValues = __webpack_require__(4); | ||
var _createStore = __webpack_require__(2); | ||
var _utilsIsPlainObject = __webpack_require__(4); | ||
var _utilsIsPlainObject2 = _interopRequireDefault(_utilsIsPlainObject); | ||
var _utilsMapValues = __webpack_require__(5); | ||
var _utilsMapValues2 = _interopRequireDefault(_utilsMapValues); | ||
var _utilsPick = __webpack_require__(11); | ||
var _utilsPick = __webpack_require__(9); | ||
var _utilsPick2 = _interopRequireDefault(_utilsPick); | ||
var _invariant = __webpack_require__(5); | ||
var _invariant = __webpack_require__(1); | ||
var _invariant2 = _interopRequireDefault(_invariant); | ||
var _Store = __webpack_require__(2); | ||
var _warning = __webpack_require__(10); | ||
var _warning2 = _interopRequireDefault(_warning); | ||
function getErrorMessage(key, action) { | ||
var actionType = action && action.type; | ||
var actionName = actionType && '"' + actionType + '"' || 'an action'; | ||
var actionName = actionType && '"' + actionType.toString() + '"' || 'an action'; | ||
@@ -475,2 +584,39 @@ return 'Reducer "' + key + '" returned undefined handling ' + actionName + '. ' + 'To ignore an action, you must explicitly return the previous state.'; | ||
function verifyStateShape(initialState, currentState) { | ||
var reducerKeys = Object.keys(currentState); | ||
if (reducerKeys.length === 0) { | ||
_warning2['default'](false, 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.'); | ||
return; | ||
} | ||
if (!_utilsIsPlainObject2['default'](initialState)) { | ||
_warning2['default'](false, 'initialState has unexpected type of "' + ({}).toString.call(initialState).match(/\s([a-z|A-Z]+)/)[1] + '". Expected initialState to be an object with the following ' + ('keys: "' + reducerKeys.join('", "') + '"')); | ||
return; | ||
} | ||
var unexpectedKeys = Object.keys(initialState).filter(function (key) { | ||
return reducerKeys.indexOf(key) < 0; | ||
}); | ||
_warning2['default'](unexpectedKeys.length === 0, 'Unexpected ' + (unexpectedKeys.length > 1 ? 'keys' : 'key') + ' ' + ('"' + unexpectedKeys.join('", "') + '" in initialState will be ignored. ') + ('Expected to find one of the known reducer keys instead: "' + reducerKeys.join('", "') + '"')); | ||
} | ||
/** | ||
* Turns an object whose values are different reducer functions, into a single | ||
* reducer function. It will call every child reducer, and gather their results | ||
* into a single state object, whose keys correspond to the keys of the passed | ||
* reducer functions. | ||
* | ||
* @param {Object} reducers An object whose values correspond to different | ||
* reducer functions that need to be combined into one. One handy way to obtain | ||
* it is to use ES6 `import * as reducers` syntax. The reducers may never return | ||
* undefined for any action. Instead, they should return their initial state | ||
* if the state passed to them was undefined, and the current state for any | ||
* unrecognized action. | ||
* | ||
* @returns {Function} A reducer function that invokes every reducer inside the | ||
* passed object, and builds a state object with the same shape. | ||
*/ | ||
function combineReducers(reducers) { | ||
@@ -483,12 +629,17 @@ var finalReducers = _utilsPick2['default'](reducers, function (val) { | ||
var reducer = finalReducers[key]; | ||
_invariant2['default'](typeof reducer(undefined, { type: _Store.ActionTypes.INIT }) !== 'undefined', 'Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined.'); | ||
_invariant2['default'](typeof reducer(undefined, { type: _createStore.ActionTypes.INIT }) !== 'undefined', 'Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined.'); | ||
var type = Math.random().toString(36).substring(7).split('').join('.'); | ||
_invariant2['default'](typeof reducer(undefined, { type: type }) !== 'undefined', 'Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + _Store.ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined.'); | ||
_invariant2['default'](typeof reducer(undefined, { type: type }) !== 'undefined', 'Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + _createStore.ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined.'); | ||
}); | ||
return function composition(state, action) { | ||
if (state === undefined) state = {}; | ||
var defaultState = _utilsMapValues2['default'](finalReducers, function () { | ||
return undefined; | ||
}); | ||
var stateShapeVerified; | ||
return _utilsMapValues2['default'](finalReducers, function (reducer, key) { | ||
return function combination(state, action) { | ||
if (state === undefined) state = defaultState; | ||
var finalState = _utilsMapValues2['default'](finalReducers, function (reducer, key) { | ||
var newState = reducer(state[key], action); | ||
@@ -498,18 +649,10 @@ _invariant2['default'](typeof newState !== 'undefined', getErrorMessage(key, action)); | ||
}); | ||
}; | ||
} | ||
module.exports = exports['default']; | ||
if (("development") !== 'production' && !stateShapeVerified) { | ||
verifyStateShape(state, finalState); | ||
stateShapeVerified = true; | ||
} | ||
/***/ }, | ||
/* 10 */ | ||
/***/ function(module, exports) { | ||
'use strict'; | ||
exports.__esModule = true; | ||
exports['default'] = isPlainObject; | ||
function isPlainObject(obj) { | ||
return obj ? typeof obj === 'object' && Object.getPrototypeOf(obj) === Object.prototype : false; | ||
return finalState; | ||
}; | ||
} | ||
@@ -520,5 +663,12 @@ | ||
/***/ }, | ||
/* 11 */ | ||
/* 9 */ | ||
/***/ function(module, exports) { | ||
/** | ||
* Picks key-value pairs from an object where values satisfy a predicate. | ||
* | ||
* @param {Object} obj The object to pick from. | ||
* @param {Function} fn The predicate the values must satisfy to be copied. | ||
* @returns {Object} The object with the values that satisfied the predicate. | ||
*/ | ||
"use strict"; | ||
@@ -540,2 +690,68 @@ | ||
/***/ }, | ||
/* 10 */ | ||
/***/ function(module, exports, __webpack_require__) { | ||
/** | ||
* Copyright 2014-2015, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
*/ | ||
'use strict'; | ||
/** | ||
* Similar to invariant but only logs a warning if the condition is not met. | ||
* This can be used to log issues in development environments in critical | ||
* paths. Removing the logging code for production environments will keep the | ||
* same logic and follow the same code paths. | ||
*/ | ||
var warning = function() {}; | ||
if (true) { | ||
warning = function(condition, format, args) { | ||
var len = arguments.length; | ||
args = new Array(len > 2 ? len - 2 : 0); | ||
for (var key = 2; key < len; key++) { | ||
args[key - 2] = arguments[key]; | ||
} | ||
if (format === undefined) { | ||
throw new Error( | ||
'`warning(condition, format, ...args)` requires a warning ' + | ||
'message argument' | ||
); | ||
} | ||
if (format.length < 10 || (/^[s\W]*$/).test(format)) { | ||
throw new Error( | ||
'The warning format should be able to uniquely identify this ' + | ||
'warning. Please, use a more descriptive format than: ' + format | ||
); | ||
} | ||
if (!condition) { | ||
var argIndex = 0; | ||
var message = 'Warning: ' + | ||
format.replace(/%s/g, function() { | ||
return args[argIndex++]; | ||
}); | ||
if (typeof console !== 'undefined') { | ||
console.error(message); | ||
} | ||
try { | ||
// This error was thrown as a convenience so that you can use this stack | ||
// to find the callsite that caused this warning to fire. | ||
throw new Error(message); | ||
} catch(x) {} | ||
} | ||
}; | ||
} | ||
module.exports = warning; | ||
/***/ } | ||
@@ -542,0 +758,0 @@ /******/ ]) |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):"object"==typeof exports?exports.Redux=t():e.Redux=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var u=n[r]={exports:{},id:r,loaded:!1};return e[r].call(u.exports,u,u.exports,t),u.loaded=!0,u.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0;var u=n(6),o=r(u),i=n(1),a=r(i),s=n(9),d=r(s),c=n(8),f=r(c),l=n(7),p=r(l),h=n(3),y=r(h);t.createStore=o.default,t.compose=a.default,t.combineReducers=d.default,t.bindActionCreators=f.default,t.applyMiddleware=p.default,t.composeMiddleware=y.default},function(e,t){"use strict";function n(){for(var e=arguments.length,t=Array(e),n=0;e>n;n++)t[n]=arguments[n];return t.reduceRight(function(e,t){return t(e)})}t.__esModule=!0,t.default=n,e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function u(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var o=n(5),i=r(o),a=n(10),s=r(a),d={INIT:"@@redux/INIT"};t.ActionTypes=d;var c=function(){function e(t,n){u(this,e),i.default("function"==typeof t,"Expected the reducer to be a function."),this.state=n,this.listeners=[],this.replaceReducer(t)}return e.prototype.getReducer=function(){return this.reducer},e.prototype.replaceReducer=function(e){this.reducer=e,this.dispatch({type:d.INIT})},e.prototype.dispatch=function(e){i.default(s.default(e),"Actions must be plain objects. Use custom middleware for async actions.");var t=this.reducer;return this.state=t(this.state,e),this.listeners.forEach(function(e){return e()}),e},e.prototype.getState=function(){return this.state},e.prototype.subscribe=function(e){var t=this.listeners;return t.push(e),function(){var n=t.indexOf(e);t.splice(n,1)}},e}();t.default=c},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function u(){for(var e=arguments.length,t=Array(e),n=0;e>n;n++)t[n]=arguments[n];return function(e){return function(n){return i.default.apply(void 0,t.map(function(t){return t(e)}).concat([n]))}}}t.__esModule=!0,t.default=u;var o=n(1),i=r(o);e.exports=t.default},function(e,t){"use strict";function n(e,t){return Object.keys(e).reduce(function(n,r){return n[r]=t(e[r],r),n},{})}t.__esModule=!0,t.default=n,e.exports=t.default},function(e,t,n){"use strict";var r=function(e,t,n,r,u,o,i,a){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var d=[n,r,u,o,i,a],c=0;s=new Error("Invariant Violation: "+t.replace(/%s/g,function(){return d[c++]}))}throw s.framesToPop=1,s}};e.exports=r},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function u(e,t){var n=new i.default(e,t);return{dispatch:n.dispatch.bind(n),subscribe:n.subscribe.bind(n),getState:n.getState.bind(n),getReducer:n.getReducer.bind(n),replaceReducer:n.replaceReducer.bind(n)}}t.__esModule=!0,t.default=u;var o=n(2),i=r(o);e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function u(){for(var e=arguments.length,t=Array(e),n=0;e>n;n++)t[n]=arguments[n];return function(e){return function(){function n(e){var t={dispatch:n,getState:r.getState};return a.default(u(t),r.dispatch)(e)}var r=e.apply(void 0,arguments),u=d.default.apply(void 0,t);return o({},r,{dispatch:n})}}}t.__esModule=!0;var o=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e};t.default=u;var i=n(1),a=r(i),s=n(3),d=r(s);e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function u(e,t){return i.default(e,function(e){return function(){return t(e.apply(void 0,arguments))}})}t.__esModule=!0,t.default=u;var o=n(4),i=r(o);e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function u(e,t){var n=t&&t.type,r=n&&'"'+n+'"'||"an action";return'Reducer "'+e+'" returned undefined handling '+r+". To ignore an action, you must explicitly return the previous state."}function o(e){var t=d.default(e,function(e){return"function"==typeof e});return Object.keys(t).forEach(function(e){var n=t[e];f.default("undefined"!=typeof n(void 0,{type:l.ActionTypes.INIT}),'Reducer "'+e+'" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined.');var r=Math.random().toString(36).substring(7).split("").join(".");f.default("undefined"!=typeof n(void 0,{type:r}),'Reducer "'+e+'" returned undefined when probed with a random type. '+("Don't try to handle "+l.ActionTypes.INIT+' or other actions in "redux/*" ')+"namespace. They are considered private. Instead, you must return the current state for any unknown actions, unless it is undefined, in which case you must return the initial state, regardless of the action type. The initial state may not be undefined.")}),function(e,n){return void 0===e&&(e={}),a.default(t,function(t,r){var o=t(e[r],n);return f.default("undefined"!=typeof o,u(r,n)),o})}}t.__esModule=!0,t.default=o;var i=n(4),a=r(i),s=n(11),d=r(s),c=n(5),f=r(c),l=n(2);e.exports=t.default},function(e,t){"use strict";function n(e){return e?"object"==typeof e&&Object.getPrototypeOf(e)===Object.prototype:!1}t.__esModule=!0,t.default=n,e.exports=t.default},function(e,t){"use strict";function n(e,t){return Object.keys(e).reduce(function(n,r){return t(e[r])&&(n[r]=e[r]),n},{})}t.__esModule=!0,t.default=n,e.exports=t.default}])}); | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):"object"==typeof exports?exports.Redux=e():t.Redux=e()}(this,function(){return function(t){function e(r){if(n[r])return n[r].exports;var u=n[r]={exports:{},id:r,loaded:!1};return t[r].call(u.exports,u,u.exports,e),u.loaded=!0,u.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}e.__esModule=!0;var u=n(2),o=r(u),i=n(8),a=r(i),c=n(7),f=r(c),d=n(6),s=r(d),l=n(3),p=r(l);e.createStore=o.default,e.combineReducers=a.default,e.bindActionCreators=f.default,e.applyMiddleware=s.default,e.compose=p.default},function(t,e,n){"use strict";var r=function(t,e,n,r,u,o,i,a){if(!t){var c;if(void 0===e)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var f=[n,r,u,o,i,a],d=0;c=new Error("Invariant Violation: "+e.replace(/%s/g,function(){return f[d++]}))}throw c.framesToPop=1,c}};t.exports=r},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function u(t,e){function n(){return s}function r(t){return l.push(t),function(){var e=l.indexOf(t);l.splice(e,1)}}function u(t){i.default(c.default(t),"Actions must be plain objects. Use custom middleware for async actions."),i.default(p===!1,"Reducers may not dispatch actions.");try{p=!0,s=d(s,t)}finally{p=!1}return l.slice().forEach(function(t){return t()}),t}function o(){return d}function a(t){d=t,u({type:f.INIT})}i.default("function"==typeof t,"Expected the reducer to be a function.");var d=t,s=e,l=[],p=!1;return u({type:f.INIT}),{dispatch:u,subscribe:r,getState:n,getReducer:o,replaceReducer:a}}e.__esModule=!0,e.default=u;var o=n(1),i=r(o),a=n(4),c=r(a),f={INIT:"@@redux/INIT"};e.ActionTypes=f},function(t,e){"use strict";function n(){for(var t=arguments.length,e=Array(t),n=0;t>n;n++)e[n]=arguments[n];return e.reduceRight(function(t,e){return e(t)})}e.__esModule=!0,e.default=n,t.exports=e.default},function(t,e){"use strict";function n(t){if(!t||"object"!=typeof t)return!1;var e="function"==typeof t.constructor?Object.getPrototypeOf(t):Object.prototype;if(null===e)return!0;var n=e.constructor;return"function"==typeof n&&n instanceof n&&r(n)===r(Object)}e.__esModule=!0,e.default=n;var r=function(t){return Function.prototype.toString.call(t)};t.exports=e.default},function(t,e){"use strict";function n(t,e){return Object.keys(t).reduce(function(n,r){return n[r]=e(t[r],r),n},{})}e.__esModule=!0,e.default=n,t.exports=e.default},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function u(){for(var t=arguments.length,e=Array(t),n=0;t>n;n++)e[n]=arguments[n];return function(t){return function(n,r){var u=t(n,r),i=u.dispatch,c=[],f={getState:u.getState,dispatch:function(t){return i(t)}};return c=e.map(function(t){return t(f)}),i=a.default.apply(void 0,c.concat([u.dispatch])),o({},u,{dispatch:i})}}}e.__esModule=!0;var o=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t};e.default=u;var i=n(3),a=r(i);t.exports=e.default},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function u(t,e){return function(){return e(t.apply(void 0,arguments))}}function o(t,e){return"function"==typeof t?u(t,e):(a.default("object"==typeof t&&null!=t,'bindActionCreators expected an object or a function, instead received %s. Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?',typeof t),f.default(t,function(t){return u(t,e)}))}e.__esModule=!0,e.default=o;var i=n(1),a=r(i),c=n(5),f=r(c);t.exports=e.default},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function u(t,e){var n=e&&e.type,r=n&&'"'+n.toString()+'"'||"an action";return'Reducer "'+t+'" returned undefined handling '+r+". To ignore an action, you must explicitly return the previous state."}function o(t){var e=s.default(t,function(t){return"function"==typeof t});Object.keys(e).forEach(function(t){var n=e[t];p.default("undefined"!=typeof n(void 0,{type:i.ActionTypes.INIT}),'Reducer "'+t+'" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined.');var r=Math.random().toString(36).substring(7).split("").join(".");p.default("undefined"!=typeof n(void 0,{type:r}),'Reducer "'+t+'" returned undefined when probed with a random type. '+("Don't try to handle "+i.ActionTypes.INIT+' or other actions in "redux/*" ')+"namespace. They are considered private. Instead, you must return the current state for any unknown actions, unless it is undefined, in which case you must return the initial state, regardless of the action type. The initial state may not be undefined.")});var n=f.default(e,function(){return void 0});return function(t,r){void 0===t&&(t=n);var o=f.default(e,function(e,n){var o=e(t[n],r);return p.default("undefined"!=typeof o,u(n,r)),o});return o}}e.__esModule=!0,e.default=o;var i=n(2),a=n(4),c=(r(a),n(5)),f=r(c),d=n(9),s=r(d),l=n(1),p=r(l),y=n(10);r(y);t.exports=e.default},function(t,e){"use strict";function n(t,e){return Object.keys(t).reduce(function(n,r){return e(t[r])&&(n[r]=t[r]),n},{})}e.__esModule=!0,e.default=n,t.exports=e.default},function(t,e,n){"use strict";var r=function(){};t.exports=r}])}); |
@@ -8,18 +8,156 @@ 'use strict'; | ||
var _Store = require('./Store'); | ||
var _invariant = require('invariant'); | ||
var _Store2 = _interopRequireDefault(_Store); | ||
var _invariant2 = _interopRequireDefault(_invariant); | ||
var _utilsIsPlainObject = require('./utils/isPlainObject'); | ||
var _utilsIsPlainObject2 = _interopRequireDefault(_utilsIsPlainObject); | ||
/** | ||
* These are private action types reserved by Redux. | ||
* For any unknown actions, you must return the current state. | ||
* If the current state is undefined, you must return the initial state. | ||
* Do not reference these action types directly in your code. | ||
*/ | ||
var ActionTypes = { | ||
INIT: '@@redux/INIT' | ||
}; | ||
exports.ActionTypes = ActionTypes; | ||
/** | ||
* Creates a Redux store that holds the state tree. | ||
* The only way to change the data in the store is to call `dispatch()` on it. | ||
* | ||
* There should only be a single store in your app. To specify how different | ||
* parts of the state tree respond to actions, you may combine several reducers | ||
* into a single reducer function by using `combineReducers`. | ||
* | ||
* @param {Function} reducer A function that returns the next state tree, given | ||
* the current state tree and the action to handle. | ||
* | ||
* @param {any} [initialState] The initial state. You may optionally specify it | ||
* to hydrate the state from the server in universal apps, or to restore a | ||
* previously serialized user session. | ||
* If you use `combineReducers` to produce the root reducer function, this must be | ||
* an object with the same shape as `combineReducers` keys. | ||
* | ||
* @returns {Store} A Redux store that lets you read the state, dispatch actions | ||
* and subscribe to changes. | ||
*/ | ||
function createStore(reducer, initialState) { | ||
var store = new _Store2['default'](reducer, initialState); | ||
_invariant2['default'](typeof reducer === 'function', 'Expected the reducer to be a function.'); | ||
var currentReducer = reducer; | ||
var currentState = initialState; | ||
var listeners = []; | ||
var isDispatching = false; | ||
/** | ||
* Reads the state tree managed by the store. | ||
* | ||
* @returns {any} The current state tree of your application. | ||
*/ | ||
function getState() { | ||
return currentState; | ||
} | ||
/** | ||
* Adds a change listener. It will be called any time an action is dispatched, | ||
* and some part of the state tree may potentially have changed. You may then | ||
* call `getState()` to read the current state tree inside the callback. | ||
* | ||
* @param {Function} listener A callback to be invoked on every dispatch. | ||
* @returns {Function} A function to remove this change listener. | ||
*/ | ||
function subscribe(listener) { | ||
listeners.push(listener); | ||
return function unsubscribe() { | ||
var index = listeners.indexOf(listener); | ||
listeners.splice(index, 1); | ||
}; | ||
} | ||
/** | ||
* Dispatches an action. It is the only way to trigger a state change. | ||
* | ||
* The `reducer` function, used to create the store, will be called with the | ||
* current state tree and the given `action`. Its return value will | ||
* be considered the **next** state of the tree, and the change listeners | ||
* will be notified. | ||
* | ||
* The base implementation only supports plain object actions. If you want to | ||
* dispatch a Promise, an Observable, a thunk, or something else, you need to | ||
* wrap your store creating function into the corresponding middleware. For | ||
* example, see the documentation for the `redux-thunk` package. Even the | ||
* middleware will eventually dispatch plain object actions using this method. | ||
* | ||
* @param {Object} action A plain object representing “what changed”. It is | ||
* a good idea to keep actions serializable so you can record and replay user | ||
* sessions, or use the time travelling `redux-devtools`. | ||
* | ||
* @returns {Object} For convenience, the same action object you dispatched. | ||
* | ||
* Note that, if you use a custom middleware, it may wrap `dispatch()` to | ||
* return something else (for example, a Promise you can await). | ||
*/ | ||
function dispatch(action) { | ||
_invariant2['default'](_utilsIsPlainObject2['default'](action), 'Actions must be plain objects. Use custom middleware for async actions.'); | ||
_invariant2['default'](isDispatching === false, 'Reducers may not dispatch actions.'); | ||
try { | ||
isDispatching = true; | ||
currentState = currentReducer(currentState, action); | ||
} finally { | ||
isDispatching = false; | ||
} | ||
listeners.slice().forEach(function (listener) { | ||
return listener(); | ||
}); | ||
return action; | ||
} | ||
/** | ||
* Returns the reducer currently used by the store to calculate the state. | ||
* | ||
* It is likely that you will only need this function if you implement a hot | ||
* reloading mechanism for Redux. | ||
* | ||
* @returns {Function} The reducer used by the current store. | ||
*/ | ||
function getReducer() { | ||
return currentReducer; | ||
} | ||
/** | ||
* Replaces the reducer currently used by the store to calculate the state. | ||
* | ||
* You might need this if your app implements code splitting and you want to | ||
* load some of the reducers dynamically. You might also need this if you | ||
* implement a hot reloading mechanism for Redux. | ||
* | ||
* @param {Function} nextReducer The reducer for the store to use instead. | ||
* @returns {void} | ||
*/ | ||
function replaceReducer(nextReducer) { | ||
currentReducer = nextReducer; | ||
dispatch({ type: ActionTypes.INIT }); | ||
} | ||
// When a store is created, an "INIT" action is dispatched so that every | ||
// reducer returns their initial state. This effectively populates | ||
// the initial state tree. | ||
dispatch({ type: ActionTypes.INIT }); | ||
return { | ||
dispatch: store.dispatch.bind(store), | ||
subscribe: store.subscribe.bind(store), | ||
getState: store.getState.bind(store), | ||
getReducer: store.getReducer.bind(store), | ||
replaceReducer: store.replaceReducer.bind(store) | ||
dispatch: dispatch, | ||
subscribe: subscribe, | ||
getState: getState, | ||
getReducer: getReducer, | ||
replaceReducer: replaceReducer | ||
}; | ||
} | ||
module.exports = exports['default']; | ||
} |
@@ -1,2 +0,1 @@ | ||
// Core | ||
'use strict'; | ||
@@ -12,8 +11,2 @@ | ||
// Utilities | ||
var _utilsCompose = require('./utils/compose'); | ||
var _utilsCompose2 = _interopRequireDefault(_utilsCompose); | ||
var _utilsCombineReducers = require('./utils/combineReducers'); | ||
@@ -31,11 +24,10 @@ | ||
var _utilsComposeMiddleware = require('./utils/composeMiddleware'); | ||
var _utilsCompose = require('./utils/compose'); | ||
var _utilsComposeMiddleware2 = _interopRequireDefault(_utilsComposeMiddleware); | ||
var _utilsCompose2 = _interopRequireDefault(_utilsCompose); | ||
exports.createStore = _createStore2['default']; | ||
exports.compose = _utilsCompose2['default']; | ||
exports.combineReducers = _utilsCombineReducers2['default']; | ||
exports.bindActionCreators = _utilsBindActionCreators2['default']; | ||
exports.applyMiddleware = _utilsApplyMiddleware2['default']; | ||
exports.composeMiddleware = _utilsComposeMiddleware2['default']; | ||
exports.compose = _utilsCompose2['default']; |
@@ -15,12 +15,17 @@ 'use strict'; | ||
var _composeMiddleware = require('./composeMiddleware'); | ||
var _composeMiddleware2 = _interopRequireDefault(_composeMiddleware); | ||
/** | ||
* Creates a higher-order store that applies middleware to a store's dispatch. | ||
* Creates a store enhancer that applies middleware to the dispatch method | ||
* of the Redux store. This is handy for a variety of tasks, such as expressing | ||
* asynchronous actions in a concise manner, or logging every action payload. | ||
* | ||
* See `redux-thunk` package as an example of the Redux middleware. | ||
* | ||
* Because middleware is potentially asynchronous, this should be the first | ||
* higher-order store in the composition chain. | ||
* @param {...Function} ...middlewares | ||
* @return {Function} A higher-order store | ||
* store enhancer in the composition chain. | ||
* | ||
* Note that each middleware will be given the `dispatch` and `getState` functions | ||
* as named arguments. | ||
* | ||
* @param {...Function} middlewares The middleware chain to be applied. | ||
* @returns {Function} A store enhancer applying the middleware. | ||
*/ | ||
@@ -34,17 +39,20 @@ | ||
return function (next) { | ||
return function () { | ||
var store = next.apply(undefined, arguments); | ||
var middleware = _composeMiddleware2['default'].apply(undefined, middlewares); | ||
return function (reducer, initialState) { | ||
var store = next(reducer, initialState); | ||
var _dispatch = store.dispatch; | ||
var chain = []; | ||
function dispatch(action) { | ||
var methods = { | ||
dispatch: dispatch, | ||
getState: store.getState | ||
}; | ||
var middlewareAPI = { | ||
getState: store.getState, | ||
dispatch: function dispatch(action) { | ||
return _dispatch(action); | ||
} | ||
}; | ||
chain = middlewares.map(function (middleware) { | ||
return middleware(middlewareAPI); | ||
}); | ||
_dispatch = _compose2['default'].apply(undefined, chain.concat([store.dispatch])); | ||
return _compose2['default'](middleware(methods), store.dispatch)(action); | ||
} | ||
return _extends({}, store, { | ||
dispatch: dispatch | ||
dispatch: _dispatch | ||
}); | ||
@@ -51,0 +59,0 @@ }; |
@@ -8,2 +8,6 @@ 'use strict'; | ||
var _invariant = require('invariant'); | ||
var _invariant2 = _interopRequireDefault(_invariant); | ||
var _utilsMapValues = require('../utils/mapValues'); | ||
@@ -13,7 +17,39 @@ | ||
function bindActionCreator(actionCreator, dispatch) { | ||
return function () { | ||
return dispatch(actionCreator.apply(undefined, arguments)); | ||
}; | ||
} | ||
/** | ||
* Turns an object whose values are action creators, into an object with the | ||
* same keys, but with every function wrapped into a `dispatch` call so they | ||
* may be invoked directly. This is just a convenience method, as you can call | ||
* `store.dispatch(MyActionCreators.doSomething())` yourself just fine. | ||
* | ||
* For convenience, you can also pass a single function as the first argument, | ||
* and get a function in return. | ||
* | ||
* @param {Function|Object} actionCreators An object whose values are action | ||
* creator functions. One handy way to obtain it is to use ES6 `import * as` | ||
* syntax. You may also pass a single function. | ||
* | ||
* @param {Function} dispatch The `dispatch` function available on your Redux | ||
* store. | ||
* | ||
* @returns {Function|Object} The object mimicking the original object, but with | ||
* every action creator wrapped into the `dispatch` call. If you passed a | ||
* function as `actionCreators`, the return value will also be a single | ||
* function. | ||
*/ | ||
function bindActionCreators(actionCreators, dispatch) { | ||
if (typeof actionCreators === 'function') { | ||
return bindActionCreator(actionCreators, dispatch); | ||
} | ||
_invariant2['default'](typeof actionCreators === 'object' && actionCreators != null, 'bindActionCreators expected an object or a function, instead received %s. ' + 'Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?', typeof actionCreators); | ||
return _utilsMapValues2['default'](actionCreators, function (actionCreator) { | ||
return function () { | ||
return dispatch(actionCreator.apply(undefined, arguments)); | ||
}; | ||
return bindActionCreator(actionCreator, dispatch); | ||
}); | ||
@@ -20,0 +56,0 @@ } |
@@ -8,2 +8,8 @@ 'use strict'; | ||
var _createStore = require('../createStore'); | ||
var _utilsIsPlainObject = require('../utils/isPlainObject'); | ||
var _utilsIsPlainObject2 = _interopRequireDefault(_utilsIsPlainObject); | ||
var _utilsMapValues = require('../utils/mapValues'); | ||
@@ -21,7 +27,9 @@ | ||
var _Store = require('../Store'); | ||
var _warning = require('warning'); | ||
var _warning2 = _interopRequireDefault(_warning); | ||
function getErrorMessage(key, action) { | ||
var actionType = action && action.type; | ||
var actionName = actionType && '"' + actionType + '"' || 'an action'; | ||
var actionName = actionType && '"' + actionType.toString() + '"' || 'an action'; | ||
@@ -31,2 +39,39 @@ return 'Reducer "' + key + '" returned undefined handling ' + actionName + '. ' + 'To ignore an action, you must explicitly return the previous state.'; | ||
function verifyStateShape(initialState, currentState) { | ||
var reducerKeys = Object.keys(currentState); | ||
if (reducerKeys.length === 0) { | ||
_warning2['default'](false, 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.'); | ||
return; | ||
} | ||
if (!_utilsIsPlainObject2['default'](initialState)) { | ||
_warning2['default'](false, 'initialState has unexpected type of "' + ({}).toString.call(initialState).match(/\s([a-z|A-Z]+)/)[1] + '". Expected initialState to be an object with the following ' + ('keys: "' + reducerKeys.join('", "') + '"')); | ||
return; | ||
} | ||
var unexpectedKeys = Object.keys(initialState).filter(function (key) { | ||
return reducerKeys.indexOf(key) < 0; | ||
}); | ||
_warning2['default'](unexpectedKeys.length === 0, 'Unexpected ' + (unexpectedKeys.length > 1 ? 'keys' : 'key') + ' ' + ('"' + unexpectedKeys.join('", "') + '" in initialState will be ignored. ') + ('Expected to find one of the known reducer keys instead: "' + reducerKeys.join('", "') + '"')); | ||
} | ||
/** | ||
* Turns an object whose values are different reducer functions, into a single | ||
* reducer function. It will call every child reducer, and gather their results | ||
* into a single state object, whose keys correspond to the keys of the passed | ||
* reducer functions. | ||
* | ||
* @param {Object} reducers An object whose values correspond to different | ||
* reducer functions that need to be combined into one. One handy way to obtain | ||
* it is to use ES6 `import * as reducers` syntax. The reducers may never return | ||
* undefined for any action. Instead, they should return their initial state | ||
* if the state passed to them was undefined, and the current state for any | ||
* unrecognized action. | ||
* | ||
* @returns {Function} A reducer function that invokes every reducer inside the | ||
* passed object, and builds a state object with the same shape. | ||
*/ | ||
function combineReducers(reducers) { | ||
@@ -39,12 +84,17 @@ var finalReducers = _utilsPick2['default'](reducers, function (val) { | ||
var reducer = finalReducers[key]; | ||
_invariant2['default'](typeof reducer(undefined, { type: _Store.ActionTypes.INIT }) !== 'undefined', 'Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined.'); | ||
_invariant2['default'](typeof reducer(undefined, { type: _createStore.ActionTypes.INIT }) !== 'undefined', 'Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined.'); | ||
var type = Math.random().toString(36).substring(7).split('').join('.'); | ||
_invariant2['default'](typeof reducer(undefined, { type: type }) !== 'undefined', 'Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + _Store.ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined.'); | ||
_invariant2['default'](typeof reducer(undefined, { type: type }) !== 'undefined', 'Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + _createStore.ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined.'); | ||
}); | ||
return function composition(state, action) { | ||
if (state === undefined) state = {}; | ||
var defaultState = _utilsMapValues2['default'](finalReducers, function () { | ||
return undefined; | ||
}); | ||
var stateShapeVerified; | ||
return _utilsMapValues2['default'](finalReducers, function (reducer, key) { | ||
return function combination(state, action) { | ||
if (state === undefined) state = defaultState; | ||
var finalState = _utilsMapValues2['default'](finalReducers, function (reducer, key) { | ||
var newState = reducer(state[key], action); | ||
@@ -54,2 +104,9 @@ _invariant2['default'](typeof newState !== 'undefined', getErrorMessage(key, action)); | ||
}); | ||
if (process.env.NODE_ENV !== 'production' && !stateShapeVerified) { | ||
verifyStateShape(state, finalState); | ||
stateShapeVerified = true; | ||
} | ||
return finalState; | ||
}; | ||
@@ -56,0 +113,0 @@ } |
/** | ||
* Composes functions from left to right | ||
* @param {...Function} funcs - Functions to compose | ||
* @return {Function} | ||
* Composes functions from left to right. | ||
* | ||
* @param {...Function} funcs - The functions to compose. Each is expected to | ||
* accept a function as an argument and to return a function. | ||
* @returns {Function} A function obtained by composing functions from left to | ||
* right. | ||
*/ | ||
@@ -6,0 +9,0 @@ "use strict"; |
@@ -5,7 +5,27 @@ 'use strict'; | ||
exports['default'] = isPlainObject; | ||
var fnToString = function fnToString(fn) { | ||
return Function.prototype.toString.call(fn); | ||
}; | ||
/** | ||
* @param {any} obj The object to inspect. | ||
* @returns {boolean} True if the argument appears to be a plain object. | ||
*/ | ||
function isPlainObject(obj) { | ||
return obj ? typeof obj === 'object' && Object.getPrototypeOf(obj) === Object.prototype : false; | ||
if (!obj || typeof obj !== 'object') { | ||
return false; | ||
} | ||
var proto = typeof obj.constructor === 'function' ? Object.getPrototypeOf(obj) : Object.prototype; | ||
if (proto === null) { | ||
return true; | ||
} | ||
var constructor = proto.constructor; | ||
return typeof constructor === 'function' && constructor instanceof constructor && fnToString(constructor) === fnToString(Object); | ||
} | ||
module.exports = exports['default']; |
@@ -0,1 +1,8 @@ | ||
/** | ||
* Applies a function to every key-value pair inside an object. | ||
* | ||
* @param {Object} obj The source object. | ||
* @param {Function} fn The mapper function taht receives the value and the key. | ||
* @returns {Object} A new object that contains the mapped values for the keys. | ||
*/ | ||
"use strict"; | ||
@@ -2,0 +9,0 @@ |
@@ -0,1 +1,8 @@ | ||
/** | ||
* Picks key-value pairs from an object where values satisfy a predicate. | ||
* | ||
* @param {Object} obj The object to pick from. | ||
* @param {Function} fn The predicate the values must satisfy to be copied. | ||
* @returns {Object} The object with the values that satisfied the predicate. | ||
*/ | ||
"use strict"; | ||
@@ -2,0 +9,0 @@ |
{ | ||
"name": "redux", | ||
"version": "1.0.0-rc", | ||
"description": "Atomic Flux with hot reloading", | ||
"version": "1.0.0", | ||
"description": "Predictable state container for JavaScript apps", | ||
"main": "lib/index.js", | ||
"jsnext:main": "src/index.js", | ||
"scripts": { | ||
"browser": "scripts/browser", | ||
"build": "scripts/build", | ||
"clean": "scripts/clean", | ||
"lint": "scripts/lint", | ||
"prepublish": "scripts/prepublish", | ||
"test": "scripts/test", | ||
"test:watch": "scripts/test-watch", | ||
"test:cov": "scripts/test-cov" | ||
"clean": "rimraf lib dist coverage", | ||
"lint": "eslint src test examples", | ||
"test": "mocha --compilers js:babel/register --recursive", | ||
"test:watch": "npm test -- --watch", | ||
"test:cov": "babel-node $(npm bin)/isparta cover $(npm bin)/_mocha -- --recursive", | ||
"check": "npm run lint && npm run test", | ||
"build:lib": "babel src --out-dir lib", | ||
"build:umd": "webpack src/index.js dist/redux.js --config webpack.config.development.js", | ||
"build:umd:min": "webpack src/index.js dist/redux.min.js --config webpack.config.production.js", | ||
"build:examples": "babel-node examples/buildAll.js", | ||
"build": "npm run build:lib && npm run build:umd && npm run build:umd:min", | ||
"preversion": "npm run clean && npm run check", | ||
"version": "npm run build", | ||
"postversion": "git push && git push --tags && npm run clean && npm run docs:publish", | ||
"prepublish": "npm run clean && npm run build", | ||
"docs:clean": "rimraf _book", | ||
"docs:build": "gitbook build -g rackt/redux", | ||
"docs:watch": "gitbook serve", | ||
"docs:publish": "npm run docs:clean && npm run docs:build && cd _book && git init && git commit --allow-empty -m 'update book' && git checkout -b gh-pages && touch .nojekyll && git add . && git commit -am 'update book' && git push git@github.com:rackt/redux gh-pages --force" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/gaearon/redux.git" | ||
"url": "https://github.com/rackt/redux.git" | ||
}, | ||
@@ -36,5 +48,5 @@ "keywords": [ | ||
"bugs": { | ||
"url": "https://github.com/gaearon/redux/issues" | ||
"url": "https://github.com/rackt/redux/issues" | ||
}, | ||
"homepage": "https://github.com/gaearon/redux", | ||
"homepage": "https://github.com/rackt/redux", | ||
"devDependencies": { | ||
@@ -45,6 +57,8 @@ "babel": "^5.5.8", | ||
"babel-loader": "^5.1.4", | ||
"contextify": "^0.1.14", | ||
"eslint": "^0.23", | ||
"eslint-config-airbnb": "0.0.6", | ||
"eslint-plugin-react": "^2.3.0", | ||
"expect": "^1.6.0", | ||
"expect": "^1.8.0", | ||
"gitbook-cli": "^0.3.4", | ||
"isparta": "^3.0.3", | ||
@@ -57,3 +71,4 @@ "mocha": "^2.2.5", | ||
"dependencies": { | ||
"invariant": "^2.0.0" | ||
"invariant": "^2.0.0", | ||
"warning": "^2.0.0" | ||
}, | ||
@@ -60,0 +75,0 @@ "npmName": "redux", |
541
README.md
@@ -1,190 +0,78 @@ | ||
redux | ||
========================= | ||
# [Redux](http://rackt.github.io/redux) | ||
[![build status](https://img.shields.io/travis/gaearon/redux/master.svg?style=flat-square)](https://travis-ci.org/gaearon/redux) | ||
[![npm version](https://img.shields.io/npm/v/redux.svg?style=flat-square)](https://www.npmjs.com/package/redux) | ||
[![redux channel on slack](https://img.shields.io/badge/slack-redux@reactiflux-61DAFB.svg?style=flat-square)](http://www.reactiflux.com) | ||
Redux is a predictable state container for JavaScript apps. | ||
Atomic Flux with hot reloading. | ||
It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as [live code editing combined with a time traveling debugger](https://github.com/gaearon/redux-devtools). | ||
**The API is likely to change a few times before we reach 1.0.**<br> | ||
**Its [surface area](http://www.youtube.com/watch?v=4anAwXYqLG8) is minimal so you can try it in production and report any issues.** | ||
You can use Redux together with [React](https://facebook.github.io/react/), or with any other view library. | ||
It is tiny (2kB) and has no dependencies. | ||
**You can track the [new docs](https://github.com/gaearon/redux/pull/140) and the [1.0 API and terminology changes](https://github.com/gaearon/redux/pull/195).** | ||
[![build status](https://img.shields.io/travis/rackt/redux/master.svg?style=flat-square)](https://travis-ci.org/rackt/redux) | ||
[![npm version](https://img.shields.io/npm/v/redux.svg?style=flat-square)](https://www.npmjs.com/package/redux) | ||
[![npm downloads](https://img.shields.io/npm/dm/redux.svg?style=flat-square)](https://www.npmjs.com/package/redux) | ||
[![redux channel on slack](https://img.shields.io/badge/slack-redux@reactiflux-61DAFB.svg?style=flat-square)](http://www.reactiflux.com) | ||
# Table of Contents | ||
### Testimonials | ||
- [Why another Flux framework?](#why-another-flux-framework) | ||
- [Philosophy & Design Goals](#philosophy--design-goals) | ||
- [The Talk](#the-talk) | ||
- [Demo](#demo) | ||
- [Examples](#examples) | ||
- [Simple Examples](#simple-examples) | ||
- [ES5 Examples](#es5-examples) | ||
- [Async and Universal Examples with Routing](#async-and-universal-examples-with-routing) | ||
- [What does it look like?](#what-does-it-look-like) | ||
- [Actions](#actions) | ||
- [Stores](#stores) | ||
- [Components](#components) | ||
- [Dumb Components](#dumb-components) | ||
- [Smart Components](#smart-components) | ||
- [Decorators](#decorators) | ||
- [React Native](#react-native) | ||
- [Initializing Redux](#initializing-redux) | ||
- [Running the same code on client and server](#running-the-same-code-on-client-and-server) | ||
- [Additional customization](#additional-customization) | ||
- [FAQ](#faq) | ||
- [How does hot reloading work?](#how-does-hot-reloading-work) | ||
- [Can I use this in production?](#can-i-use-this-in-production) | ||
- [How do I do async?](#how-do-i-do-async) | ||
- [But there are switch statements!](#but-there-are-switch-statements) | ||
- [What about `waitFor`?](#what-about-waitfor) | ||
- [My views aren't updating!](#my-views-arent-updating) | ||
- [How do Stores, Actions and Components interact?](#how-do-stores-actions-and-components-interact) | ||
- [Discussion](#discussion) | ||
- [Inspiration and Thanks](#inspiration-and-thanks) | ||
>[“Love what you’re doing with Redux”](https://twitter.com/jingc/status/616608251463909376) | ||
>Jing Chen, creator of Flux | ||
## Why another Flux framework? | ||
>[“I asked for comments on Redux in FB's internal JS discussion group, and it was universally praised. Really awesome work.”](https://twitter.com/fisherwebdev/status/616286955693682688) | ||
>Bill Fisher, creator of Flux | ||
Read **[The Evolution of Flux Frameworks](https://medium.com/@dan_abramov/the-evolution-of-flux-frameworks-6c16ad26bb31)** for some context. | ||
>[“It's cool that you are inventing a better Flux by not doing Flux at all.”](https://twitter.com/andrestaltz/status/616271392930201604) | ||
>André Staltz, creator of Cycle | ||
### Philosophy & Design Goals | ||
### Developer Experience | ||
* You shouldn't need a book on functional programming to use Redux. | ||
* Everything (Stores, Action Creators, configuration) is hot reloadable. | ||
* Preserves the benefits of Flux, but adds other nice properties thanks to its functional nature. | ||
* Prevents some of the anti-patterns common in Flux code. | ||
* Works great in [universal (aka “isomorphic”)](https://medium.com/@mjackson/universal-javascript-4761051b7ae9) apps because it doesn't use singletons and the data can be rehydrated. | ||
* Doesn't care how you store your data: you may use JS objects, arrays, ImmutableJS, etc. | ||
* Under the hood, it keeps all your data in a tree, but you don't need to think about it. | ||
* Lets you efficiently subscribe to finer-grained updates than individual Stores. | ||
* Provides hooks for powerful devtools (e.g. time travel, record/replay) to be implementable without user buy-in. | ||
* Provides extension points so it's easy to [support promises](https://github.com/gaearon/redux/issues/99#issuecomment-112212639) or [generate constants](https://gist.github.com/skevy/8a4ffc3cfdaf5fd68739) outside the core. | ||
* No wrapper calls in your stores and actions. Your stuff is your stuff. | ||
* It's super easy to test things in isolation without mocks. | ||
* You can use “flat” Stores, or [compose and reuse Stores](https://gist.github.com/gaearon/d77ca812015c0356654f) just like you compose Components. | ||
* The API surface area is minimal. | ||
* Have I mentioned hot reloading yet? | ||
I wrote Redux while working on my React Europe talk called [“Hot Reloading with Time Travel”](https://www.youtube.com/watch?v=xsSnOQynTHs). My goal was to create a state management library with minimal API but completely predictable behavior, so it is possible to implement logging, hot reloading, time travel, universal apps, record and replay, without any buy-in from the developer. | ||
## The Talk | ||
### Influences | ||
Redux was demoed together with **[React Hot Loader](https://github.com/gaearon/react-hot-loader)** at React Europe. | ||
Watch **[Dan Abramov's talk on Hot Reloading with Time Travel](https://www.youtube.com/watch?v=xsSnOQynTHs).** | ||
Redux evolves the ideas of [Flux](https://facebook.github.io/flux), but avoids its complexity by taking cues from [Elm](http://elm-lang.org/guide/architecture). | ||
Whether you used them or not, Redux takes a few minutes to get started with. | ||
## Demo | ||
### Installation | ||
<img src='https://s3.amazonaws.com/f.cl.ly/items/2Z2D3U260d2A311k2B0z/Screen%20Recording%202015-06-03%20at%2003.22%20pm.gif' width='500'> | ||
To install the stable version: | ||
## Examples | ||
### Simple Examples | ||
Redux is distributed with a Counter and a TodoMVC example in its source code. | ||
First, clone the repo: | ||
``` | ||
git clone https://github.com/gaearon/redux.git | ||
cd redux | ||
npm install --save redux | ||
``` | ||
Run the Counter example: | ||
Most likely, you’ll also need [the React bindings](http://github.com/gaearon/react-redux) and [the developer tools](http://github.com/gaearon/redux-devtools). | ||
``` | ||
cd redux/examples/counter | ||
npm install | ||
npm start | ||
npm install --save react-redux | ||
npm install --save-dev redux-devtools | ||
``` | ||
Run the TodoMVC example: | ||
### The Gist | ||
``` | ||
cd ../todomvc | ||
npm install | ||
npm start | ||
``` | ||
The whole state of your app is stored in an object tree inside a single *store*. | ||
The only way to change the state tree is to emit an *action*, an object describing what happened. | ||
To specify how the state tree is transformed by the actions, you write pure *reducers*. | ||
### ES5 Examples | ||
That’s it! | ||
If you have not used ES6 before, check out one of these ES5 examples: | ||
* [redux-todomvc-es5](https://github.com/insin/redux-todomvc-es5) | ||
### Async and Universal Examples with Routing | ||
These async and [universal (aka “isomorphic”)](https://medium.com/@mjackson/universal-javascript-4761051b7ae9) examples using React Router should help you get started: | ||
* [redux-react-router-async-example](https://github.com/emmenko/redux-react-router-async-example): Work in progress. Semi-official. Only the client side. Uses React Router. | ||
* [react-redux-universal-hot-example](https://github.com/erikras/react-redux-universal-hot-example): Universal. Uses React Router. | ||
* [redux-example](https://github.com/quangbuule/redux-example): Universal. Uses Immutable, React Router. | ||
* [isomorphic-counter-example](https://github.com/khtdr/redux-react-koa-isomorphic-counter-example): Universal. A bare-bone implementation of the [counter example app](https://github.com/gaearon/redux/tree/master/examples/counter). Uses promises-middleware to interact with API via Koa on the server. | ||
* [Awesome list](https://github.com/xgrommx/awesome-redux) | ||
Don’t be shy, add your own! | ||
## What does it look like? | ||
### Actions | ||
```js | ||
// Still using constants... | ||
import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../constants/ActionTypes'; | ||
import { createStore } from 'redux'; | ||
// But action creators are pure functions returning actions | ||
export function increment() { | ||
return { | ||
type: INCREMENT_COUNTER | ||
}; | ||
} | ||
export function decrement() { | ||
return { | ||
type: DECREMENT_COUNTER | ||
}; | ||
} | ||
// Can also be async if you return a function | ||
export function incrementAsync() { | ||
return dispatch => { | ||
setTimeout(() => { | ||
// Yay! Can invoke sync or async actions with `dispatch` | ||
dispatch(increment()); | ||
}, 1000); | ||
}; | ||
} | ||
// Could also read state of a store in the callback form | ||
export function incrementIfOdd() { | ||
return (dispatch, getState) => { | ||
const { counter } = getState(); | ||
if (counter % 2 === 0) { | ||
return; | ||
} | ||
dispatch(increment()); | ||
}; | ||
} | ||
``` | ||
### Stores | ||
```js | ||
// ... too, use constants | ||
import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../constants/ActionTypes'; | ||
// what's important is that Store is a pure function, | ||
// and you can write it anyhow you like. | ||
// the Store signature is (state, action) => state, | ||
// and the state shape is up to you: you can use primitives, | ||
// objects, arrays, or even ImmutableJS objects. | ||
export default function counter(state = 0, action) { | ||
// this function returns the new state when an action comes | ||
/** | ||
* This is a reducer, a pure function with (state, action) => state signature. | ||
* It describes how an action transforms the state into the next state. | ||
* | ||
* The shape of the state is up to you: it can be a primitive, an array, an object, | ||
* or even an Immutable.js data structure. The only important part is you should | ||
* return a new object if the state changes, instead of mutating the parameter. | ||
* | ||
* In this example, we use a `switch` statement and strings, but you can use a helper that | ||
* follows a different convention (such as function maps) that makes sense for your project. | ||
*/ | ||
function counter(state = 0, action) { | ||
switch (action.type) { | ||
case INCREMENT_COUNTER: | ||
case 'INCREMENT': | ||
return state + 1; | ||
case DECREMENT_COUNTER: | ||
case 'DECREMENT': | ||
return state - 1; | ||
@@ -194,311 +82,70 @@ default: | ||
} | ||
// BUT THAT'S A SWITCH STATEMENT! | ||
// Right. If you hate 'em, see the FAQ below. | ||
} | ||
``` | ||
### Components | ||
// Create a Redux store that holds the state of your app. | ||
// Its API is { subscribe, dispatch, getState }. | ||
let store = createStore(counter); | ||
#### Dumb Components | ||
```js | ||
// The dumb component receives everything using props: | ||
import React, { PropTypes } from 'react'; | ||
export default class Counter { | ||
static propTypes = { | ||
increment: PropTypes.func.isRequired, | ||
decrement: PropTypes.func.isRequired, | ||
counter: PropTypes.number.isRequired | ||
}; | ||
render() { | ||
const { increment, decrement, counter } = this.props; | ||
return ( | ||
<p> | ||
Clicked: {counter} times | ||
{' '} | ||
<button onClick={increment}>+</button> | ||
{' '} | ||
<button onClick={decrement}>-</button> | ||
</p> | ||
); | ||
} | ||
} | ||
``` | ||
#### Smart Components | ||
```js | ||
// The smart component may observe stores using `<Connector />`, | ||
// and bind actions to the dispatcher with `bindActionCreators`. | ||
import React from 'react'; | ||
import { bindActionCreators } from 'redux'; | ||
import { Connector } from 'redux/react'; | ||
import Counter from '../components/Counter'; | ||
import * as CounterActions from '../actions/CounterActions'; | ||
// You can optionally specify `select` for finer-grained subscriptions | ||
// and retrieval. Only when the return value is shallowly different, | ||
// will the child component be updated. | ||
function select(state) { | ||
return { counter: state.counter }; | ||
} | ||
export default class CounterApp { | ||
render() { | ||
return ( | ||
<Connector select={select}> | ||
{({ counter, dispatch }) => | ||
/* Yes this is child as a function. */ | ||
<Counter counter={counter} | ||
{...bindActionCreators(CounterActions, dispatch)} /> | ||
} | ||
</Connector> | ||
); | ||
} | ||
} | ||
``` | ||
#### Decorators | ||
The `@connect` decorator lets you create smart components less verbosely: | ||
```js | ||
import React from 'react'; | ||
import { bindActionCreators } from 'redux'; | ||
import { connect } from 'redux/react'; | ||
import Counter from '../components/Counter'; | ||
import * as CounterActions from '../actions/CounterActions'; | ||
@connect(state => ({ | ||
counter: state.counter | ||
})) | ||
export default class CounterApp { | ||
render() { | ||
const { counter, dispatch } = this.props; | ||
// Instead of `bindActionCreators`, you may also pass `dispatch` as a prop | ||
// to your component and call `dispatch(CounterActions.increment())` | ||
return ( | ||
<Counter counter={counter} | ||
{...bindActionCreators(CounterActions, dispatch)} /> | ||
); | ||
} | ||
} | ||
``` | ||
### React Native | ||
To use Redux with React Native, just replace imports from `redux/react` with `redux/react-native`: | ||
```js | ||
import { bindActionCreators } from 'redux'; | ||
import { Provider, Connector } from 'redux/react-native'; | ||
``` | ||
### Initializing Redux | ||
The simplest way to initialize a Redux instance is to give it an object whose values are your Store functions, and whose keys are their names. You may `import *` from the file with all your Store definitions to obtain such an object: | ||
```js | ||
import { createRedux } from 'redux'; | ||
import { Provider } from 'redux/react'; | ||
import * as stores from '../stores/index'; | ||
const redux = createRedux(stores); | ||
``` | ||
Then pass `redux` as a prop to `<Provider>` component in the root component of your app, and you're all set: | ||
```js | ||
export default class App { | ||
render() { | ||
return ( | ||
<Provider redux={redux}> | ||
{() => | ||
<CounterApp /> | ||
} | ||
</Provider> | ||
); | ||
} | ||
} | ||
``` | ||
### Running the same code on client and server | ||
The `redux` instance returned by `createRedux` also has the `dispatch(action)`, `subscribe()` and `getState()` methods that you may call outside the React components. | ||
You may optionally specify the initial state as the second argument to `createRedux`. This is useful for hydrating the state you received from running Redux on the server: | ||
```js | ||
// server | ||
const redux = createRedux(stores); | ||
redux.dispatch(MyActionCreators.doSomething()); // fire action creators to fill the state | ||
const state = redux.getState(); // somehow pass this state to the client | ||
// client | ||
const initialState = window.STATE_FROM_SERVER; | ||
const redux = createRedux(stores, initialState); | ||
``` | ||
### Additional customization | ||
There is also a longer way to do the same thing, if you need additional customization. | ||
This: | ||
```js | ||
import { createRedux } from 'redux'; | ||
import * as stores from '../stores/index'; | ||
const redux = createRedux(stores); | ||
``` | ||
is in fact a shortcut for this: | ||
```js | ||
import { createRedux, createDispatcher, composeStores } from 'redux'; | ||
import thunkMiddleware from 'redux/lib/middleware/thunk'; | ||
import * as stores from '../stores/index'; | ||
// Compose all your Stores into a single Store function with `composeStores`: | ||
const store = composeStores(stores); | ||
// Create a Dispatcher function for your composite Store: | ||
const dispatcher = createDispatcher( | ||
store, | ||
getState => [thunkMiddleware(getState)] // Pass the default middleware | ||
// You can subscribe to the updates manually, or use bindings to your view layer. | ||
store.subscribe(() => | ||
console.log(store.getState()) | ||
); | ||
// Create a Redux instance using the dispatcher function: | ||
const redux = createRedux(dispatcher); | ||
// The only way to mutate the internal state is to dispatch an action. | ||
// The actions can be serialized, logged or stored and later replayed. | ||
store.dispatch({ type: 'INCREMENT' }); | ||
// 1 | ||
store.dispatch({ type: 'INCREMENT' }); | ||
// 2 | ||
store.dispatch({ type: 'DECREMENT' }); | ||
// 1 | ||
``` | ||
Why would you want to write it longer? Maybe you're an advanced user and want to provide a custom Dispatcher function, or maybe you have a different idea of how to compose your Stores (or you're satisfied with a single Store). Redux lets you do all of this. | ||
Instead of mutating the state directly, you specify the mutations you want to happen with plain objects called *actions*. Then you write a special function called a *reducer* to decide how every action transforms the entire application’s state. | ||
`createDispatcher()` also gives you the ability to specify middleware -- for example, to add support for promises. [Learn more](https://github.com/gaearon/redux/blob/master/docs/middleware.md) about how to create and use middleware in Redux. | ||
If you’re coming from Flux, there is a single important difference you need to understand. Redux doesn’t have a Dispatcher or support many stores. Instead, there is just a single store with a single root reducing function. As your app grows, instead of adding stores, you split the root reducer into smaller reducers independently operating on the different parts of the state tree. This is exactly like there is just one root component in a React app, but it is composed out of many small components. | ||
When in doubt, use the shorter option! | ||
This architecture might seem like an overkill for a counter app, but the beauty of this pattern is how well it scales to large and complex apps. It also enables very powerful developer tools, because it is possible to trace every mutation to the action that caused it. You can record user sessions and reproduce them just by replaying every action. | ||
## FAQ | ||
### Documentation | ||
### How does hot reloading work? | ||
* [Introduction](http://rackt.github.io/redux/docs/introduction/index.html) | ||
* [Basics](http://rackt.github.io/redux/docs/basics/index.html) | ||
* [Advanced](http://rackt.github.io/redux/docs/advanced/index.html) | ||
* [Recipes](http://rackt.github.io/redux/docs/recipes/index.html) | ||
* [Troubleshooting](http://rackt.github.io/redux/docs/Troubleshooting.html) | ||
* [Glossary](http://rackt.github.io/redux/docs/Glossary.html) | ||
* [API Reference](http://rackt.github.io/redux/docs/api/index.html) | ||
* http://webpack.github.io/docs/hot-module-replacement.html | ||
* http://gaearon.github.io/react-hot-loader/ | ||
* Literally that's it. Redux is fully driven by component props, so it works on top of React Hot Loader. | ||
### Discussion | ||
### Can I use this in production? | ||
Join the **#redux** channel of the [Reactiflux](http://reactiflux.com/) Slack community. | ||
Yep. People already do that although I warned them! The API surface is minimal so migrating to 1.0 API when it comes out won't be difficult. Let us know about any issues. | ||
### Thanks | ||
### How do I do async? | ||
* [The Elm Architecture](https://github.com/evancz/elm-architecture-tutorial) for a great intro to modeling state updates with reducers; | ||
* [Turning the database inside-out](http://blog.confluent.io/2015/03/04/turning-the-database-inside-out-with-apache-samza/) for blowing my mind; | ||
* [Developing ClojureScript with Figwheel](http://www.youtube.com/watch?v=j-kj2qwJa_E) for convincing me that re-evaluation should “just work”; | ||
* [Webpack](https://github.com/webpack/docs/wiki/hot-module-replacement-with-webpack) for Hot Module Replacement; | ||
* [Flummox](https://github.com/acdlite/flummox) for teaching me to approach Flux without boilerplate or singletons; | ||
* [disto](https://github.com/threepointone/disto) for a proof of concept of hot reloadable Stores; | ||
* [NuclearJS](https://github.com/optimizely/nuclear-js) for proving this architecture can be performant; | ||
* [Om](https://github.com/omcljs/om) for popularizing the idea of a single state atom; | ||
* [Cycle](https://github.com/staltz/cycle) for showing how often a function is the best tool; | ||
* [React](https://github.com/facebook/react) for the pragmatic innovation. | ||
There's already a built-in way of doing async action creators: | ||
Special thanks to [Jamie Paton](http://jdpaton.github.io/) for handing over the `redux` NPM package name. | ||
```js | ||
// Can also be async if you return a function | ||
export function incrementAsync() { | ||
return dispatch => { | ||
setTimeout(() => { | ||
// Yay! Can invoke sync or async actions with `dispatch` | ||
dispatch(increment()); | ||
}, 1000); | ||
}; | ||
} | ||
``` | ||
### Patrons | ||
It's also easy to implement support for returning Promises or Observables with a custom middleware. [See an example of a custom Promise middleware.](https://github.com/gaearon/redux/issues/99#issuecomment-112212639) | ||
The work on Redux was [funded by the community](https://www.patreon.com/reactdx). | ||
Meet some of the outstanding companies that made it possible: | ||
### But there are switch statements! | ||
* [Webflow](http://webflow.com/) | ||
* [Chess iX](http://www.chess-ix.com/) | ||
`(state, action) => state` is as simple as a Store can get. You are free to implement your own `createStore`: | ||
[See the full list of Redux patrons.](PATRONS.md) | ||
```js | ||
export default function createStore(initialState, handlers) { | ||
return (state = initialState, action) => | ||
handlers[action.type] ? | ||
handlers[action.type](state, action) : | ||
state; | ||
} | ||
``` | ||
### License | ||
and use it for your Stores: | ||
```js | ||
export default createStore(0, { | ||
[INCREMENT_COUNTER]: x => x + 1, | ||
[DECREMENT_COUNTER]: x => x - 1 | ||
}); | ||
``` | ||
It's all just functions. | ||
Fancy stuff like generating stores from handler maps, or generating action creator constants, should be in userland. | ||
Redux has no opinion on how you do this in your project. | ||
See also [this gist](https://gist.github.com/skevy/8a4ffc3cfdaf5fd68739) for an example implementation of action constant generation. | ||
### What about `waitFor`? | ||
I wrote a lot of vanilla Flux code and my only use case for it was to avoid emitting a change before a related Store consumes the action. This doesn't matter in Redux because the change is only emitted after *all* Stores have consumed the action. | ||
If several of your Stores want to read data from each other and depend on each other, it's a sign that they should've been a single Store instead. [See this discussion on how `waitFor` can be replaced by the composition of stateless Stores.](https://gist.github.com/gaearon/d77ca812015c0356654f) | ||
### My views aren't updating! | ||
Redux makes a hard assumption that you never mutate the state passed to you. It's easy! For example, instead of | ||
```js | ||
function (state, action) { | ||
state.isAuthenticated = true; | ||
state.email = action.email; | ||
return state; | ||
} | ||
``` | ||
you should write | ||
```js | ||
function (state, action) { | ||
return { | ||
...state, | ||
isAuthenticated: true, | ||
email: action.email | ||
}; | ||
} | ||
``` | ||
[Read more](https://github.com/sebmarkbage/ecmascript-rest-spread) about the spread properties ES7 proposal. | ||
### How do Stores, Actions and Components interact? | ||
Action creators are just pure functions so they don't interact with anything. Components need to call `dispatch(action)` (or use `bindActionCreators` that wraps it) to dispatch an action *returned* by the action creator. | ||
Stores are just pure functions too so they don't need to be “registered” in the traditional sense, and you can't subscribe to them directly. They're just descriptions of how data transforms. So in that sense they don't “interact” with anything either, they just exist, and are used by the dispatcher for computation of the next state. | ||
Now, the dispatcher is more interesting. You pass all the Stores to it, and it composes them into a single Store function that it uses for computation. The dispatcher is also a pure function, and it is passed as configuration to `createRedux`, the only stateful thing in Redux. By default, the default dispatcher is used, so if you call `createRedux(stores)`, it is created implicitly. | ||
To sum it up: there is a Redux instance at the root of your app. It binds everything together. It accepts a dispatcher (which itself accepts Stores), it holds the state, and it knows how to turn actions into state updates. Everything else (components, for example) subscribes to the Redux instance. If something wants to dispatch an action, they need to do it on the Redux instance. `Connector` is a handy shortcut for subscribing to a slice of the Redux instance's state and injecting `dispatch` into your components, but you don't have to use it. | ||
There is no other “interaction” in Redux. | ||
## Discussion | ||
Join the **#redux** channel of the [Reactiflux](http://reactiflux.com/) Slack community | ||
## Inspiration and Thanks | ||
* [Webpack](https://github.com/webpack/docs/wiki/hot-module-replacement-with-webpack) for Hot Module Replacement | ||
* [The Elm Architecture](https://github.com/evancz/elm-architecture-tutorial) for a great intro to “stateless Stores” | ||
* [Turning the database inside-out](http://blog.confluent.io/2015/03/04/turning-the-database-inside-out-with-apache-samza/) for blowing my mind | ||
* [Developing ClojureScript with Figwheel](http://www.youtube.com/watch?v=j-kj2qwJa_E) for convincing me that re-evaluation should “just work” | ||
* [Flummox](https://github.com/acdlite/flummox) for teaching me to approach Flux without boilerplate or singletons | ||
* [disto](https://github.com/threepointone/disto) for a proof of concept of hot reloadable Stores | ||
* [NuclearJS](https://github.com/optimizely/nuclear-js) for proving this architecture can be performant | ||
* [Om](https://github.com/omcljs/om) for popularizing the idea of a single state atom | ||
* [Cycle](https://github.com/staltz/cycle) for showing how often a function is the best tool | ||
* [React](https://github.com/facebook/react) for the pragmatic innovation | ||
Special thanks go to [Jamie Paton](http://jdpaton.github.io/) for handing over the `redux` NPM package name. | ||
MIT |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
0
96947
2
15
35
1420
151
+ Addedwarning@^2.0.0
+ Addedwarning@2.1.0(transitive)