-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove dispatcher (WIP) #166
Conversation
I really, really like this approach. The only objection that comes to mind regards terminology. I think we need distinct terms for "dispatch-level middleware" (I've called it "action middleware" elsewhere) and the "Redux-level middleware" you describe in #113 (comment). Although conceptually they are both middleware, it would be confusing to call them both by such similar names. Also, since we're going to rename the Redux class to Store, the API will actually be |
Oh and just to be clear, I do think we should have separate concepts for dispatch-level "middleware" and store-level "middleware". While it's true that dispatch-level middleware can be implemented as store-level middleware, the concerns are different. Dispatch-level middleware is concerned only with transforming a stream of actions, whereas store-level middleware is concerned with transforming both the action stream and the stream of state atoms. Also, dispatch-level middleware really needs to occur first: before it is sent through a chain of composed reduxes/stores. See the point raised by @leoasis #113 (comment). |
@gaearon Okay, haha, now I get what you meant by this:
So then I think we're in agreement! This should be a helper called something like function applyMiddleware(store, middlewares) {
// Dispatch actually comes last, not first
return {...store, dispatch: composeMiddleware(...middlewares, store.dispatch) }
} This should always be the last higher-order store before giving it the Provider, that way the action stream is transformed before it gets to time machine et al. const store = applyMiddleware(createDebugStore(reducer), middlewares);
const timeMachine = store.timeMachine;
<Provider store={store} />
<Provider store={timeMachine} /> *Can we please call it that? The more I say it the more I like it. |
Yeah that's what I wanted! |
@gaearon What do you think of the term "higher-order store" and using "middleware" exclusively for action middleware? |
@gaearon Suggestion: higher-order stores should accept a store, not the reducer. So // This
const store = createDebuggerStore(createStore(reducer));
// instead of this
const store = createDebuggerStore(reducer); That way they can be composed. (In fact, they can be composed using the same function we use to compose middleware.) |
I don't like composing Stores because I want there to be only a single source of truth in the app. Either a “simple” Store (production), or a “powerful” Store that the time travely thing “dumbs down” so it looks like “simple” store to the app (development). If there are two Stores, there is no single source of truth, is there? Seems like unnecessary overhead to me. Also, we'd need to extract the inner Store's reducer anyway because that's the only thing from it that the “powerful” Store actually cares about. |
There aren't two stores, there's a single store and multiple proxies (or higher-order stores). The internals are the same as your proposal, just a slightly different API. |
In the end we seem to have converged with @acdlite on the time travelling signature being |
I'd appreciate somebody helping out here. I'm still busy with my talk so I'm unlikely to finish this before July begins. |
* “Stateless Stores” are now called reducers. (#137 (comment)) * The “Redux instance” is now called “The Store”. (#137 (comment)) * The dispatcher is removed completely. (#166 (comment)) * <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). * The `dispatch` provided by the default thunk middleware now walks the whole middleware chain. * It is enforced now that Actions have to be plain object. Use middleware for transforming anything else into the actions. * 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.
Naming: * “Stateless Stores” are now called reducers. (#137 (comment)) * The “Redux instance” is now called “The Store”. (#137 (comment)) * The dispatcher is removed completely. (#166 (comment)) 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). * The `dispatch` provided by the default thunk middleware now walks the whole middleware chain. * It is enforced now that Actions have to be plain object. Use middleware for transforming anything else into the actions. 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.
Naming: * “Stateless Stores” are now called reducers. (#137 (comment)) * The “Redux instance” is now called “The Store”. (#137 (comment)) * The dispatcher is removed completely. (#166 (comment)) 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). * 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. 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.
Superseded by #195. |
Naming: * “Stateless Stores” are now called reducers. (#137 (comment)) * The “Redux instance” is now called “The Store”. (#137 (comment)) * The dispatcher is removed completely. (#166 (comment)) 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) 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.
Naming: * “Stateless Stores” are now called reducers. (#137 (comment)) * The “Redux instance” is now called “The Store”. (#137 (comment)) * The dispatcher is removed completely. (#166 (comment)) 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) 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.
Naming: * “Stateless Stores” are now called reducers. (reduxjs/redux#137 (comment)) * The “Redux instance” is now called “The Store”. (reduxjs/redux#137 (comment)) * The dispatcher is removed completely. (reduxjs/redux#166 (comment)) 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: reduxjs/redux#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. (reduxjs/redux#110) 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.
Naming: * “Stateless Stores” are now called reducers. (reduxjs/redux#137 (comment)) * The “Redux instance” is now called “The Store”. (reduxjs/redux#137 (comment)) * The dispatcher is removed completely. (reduxjs/redux#166 (comment)) 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: reduxjs/redux#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. (reduxjs/redux#110) 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.
Naming: * “Stateless Stores” are now called reducers. (reduxjs/redux#137 (comment)) * The “Redux instance” is now called “The Store”. (reduxjs/redux#137 (comment)) * The dispatcher is removed completely. (reduxjs/redux#166 (comment)) 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: reduxjs/redux#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. (reduxjs/redux#110) 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.
This begins to simplify the API to allow #113 (comment). It simply removes the dispatcher because it turns out to be unneeded. This also makes
createRedux(reducer: Object | Function)
make more sense as the shortcut.I think this supersedes #119.
What's lacking:
Ideally I'd like to implement middleware API proposed in #120, but not inside
Redux
—instead, we'd call compose insidecreateRedux
helper. I think that divides their responsibilities better. Technically, I'd prefer the “new” dispatch middleware to be implemented by wrapping the dispatch function and returning something like{ ...redux, dispatch: composeMiddleware(redux.dispatch, ...middlewares) }
fromcreateDispatch(reducer, ...middlewares)
. This would match the wrapping approach suggested here for implementing time travel, but on a smaller (and much more restricted) scale.If somebody would like to re-implement dispatch middleware like I suggested above in this branch, please feel free to!
cc @acdlite