From c8c788c0036893f55f99d85ff920745f4db34c62 Mon Sep 17 00:00:00 2001 From: Sam Bakkila Date: Mon, 24 Jul 2017 19:31:45 -0400 Subject: [PATCH 1/5] add design decisions to FAQ document --- docs/FAQ.md | 7 ++++ docs/faq/DesignDecisions.md | 75 +++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 docs/faq/DesignDecisions.md diff --git a/docs/FAQ.md b/docs/FAQ.md index 2c750d8279..c45840e3c6 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -43,6 +43,13 @@ - [Do I have to deep-clone my state in a reducer? Isn't copying my state going to be slow?](/docs/faq/Performance.md#performance-clone-state) - [How can I reduce the number of store update events?](/docs/faq/Performance.md#performance-update-events) - [Will having “one state tree” cause memory problems? Will dispatching many actions take up memory?](/docs/faq/Performance.md#performance-state-memory) +- **Design Decisions** + - [Why doesn't Redux pass the state and action to subscribers?](/docs/faq/DesignDecisions.md#does-not-pass-state-action-to-subscribers) + - [Why doesn't Redux support using classes for actions and reducers?](/docs/faq/DesignDecisions.md#does-not-support-classes) + - [Why does the middleware signature use currying?](/docs/faq/DesignDecisions.md#why-currying) + - [Why does applyMiddleware use a closure for dispatch?](/docs/faq/DesignDecisions.md#closure-dispatch) + - [Can you please change combineReducers to support nested state trees?](/docs/faq/DesignDecisions.md#combineReducers-limitations) + - [Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()?](/docs/faq/DesignDecisions.md#no-asynch-in-mapDispatchToProps) - **React Redux** - [Why isn't my component re-rendering, or my mapStateToProps running?](/docs/faq/ReactRedux.md#react-not-rerendering) - [Why is my component re-rendering too often?](/docs/faq/ReactRedux.md#react-rendering-too-often) diff --git a/docs/faq/DesignDecisions.md b/docs/faq/DesignDecisions.md new file mode 100644 index 0000000000..1f96388c2f --- /dev/null +++ b/docs/faq/DesignDecisions.md @@ -0,0 +1,75 @@ +# Redux FAQ: Design Decisions + +## Table of Contents + +- [Why doesn't Redux pass the state and action to subscribers?](#does-not-pass-state-action-to-subscribers) +- [Why doesn't Redux support using classes for actions and reducers?](#does-not-support-classes) +- [Why does the middleware signature use currying?](#why-currying) +- [Why does applyMiddleware use a closure for dispatch?](#closure-dispatch) +- [Can you please change combineReducers to support nested state trees?](#combineReducers-limitations) +- [Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()?](#no-asynch-in-mapDispatchToProps) + + +## Design Decisions + + +### Why doesn't Redux pass the state and action to subscribers? +Subscribers are intended to respond to the state value itself, not the action. Updates to the state are not always processed synchronously, because Redux sometimes processes actions in batches to optimize performance and repeated re-rendering. The intended guarantee is that Redux eventually calls all subscribers with the most recent state, but not that it always calls each subscriber for each action. The store state is available in the subscriber simply by calling store.getState(). The action cannot be made available in the subsribers without breaking the way that actions are batched. + +A potential use-case for using the action inside a subscriber -- which is an unsupported feature -- is to ensure that a component only re-renders after certain kinds of actions. Re-rendering should instead be controlled instead through: +1.) the [shouldComponentUpdate](https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate) lifecycle method +2.) the [virtual DOM equality check (vDOMEq)](https://facebook.github.io/react/docs/optimizing-performance.html#avoid-reconciliation) +3.) [React.PureComponent](https://facebook.github.io/react/docs/optimizing-performance.html#examples) +4.) Using React-Redux: use [mapStateToProps](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) to subscribe components to only the parts of the store that they need. + + +### Why doesn't Redux support using classes for actions and reducers? +The pattern of using functions, called action creators, to return action objects may seem counterintuitive to programmers with a lot of Object Oriented Programming experience, who would see this is a strong use-case for Classes and instances. Class instances for action objects and reducers are not supported because class instances make serialization and deserialization tricky. Deserialization methods like JSON.parse(string) will return a plain old Javascript object rather than class instances. + +Serialization enables the brower to store all actions that have been dispatched, as well as the previous store states, with much less memory. Rewinding and 'hot reloading' the store is central to the Redux developer experience and the function of Redux DevTools. This also enables deserialized actions to be stored on the server and re-serialized in the brower in the case of server-side rendering with Redux. + + +### Why does the middleware signature use currying? +The [curried function signature](https://github.com/reactjs/redux/issues/1744) of declaring middleware is [deemed unnecessary](https://github.com/reactjs/redux/pull/784) by some, because both store and next are available when the applyMiddleware function is executed. This issue has been determined to not be [worth introducing breaking changes](https://github.com/reactjs/redux/issues/1744). + + +### Why does applyMiddleware use a closure for dispatch? +applyMiddleware takes the existing dispatch from the store and closes over it to create the initial chain of middlewares that have been invoked with an object that exposes the getState and dispatch functions, which enables middlewares that [rely on dispatch during initialization](https://github.com/reactjs/redux/pull/1592) to run. + + +### Can you please change combineReducers to support nested state trees? +No, but there are some limits to combineReducers that are worth knowing. +- combineReducers receives an object where the values are all reducer names. Additional nesting is not possible, which limits the state shape. The following code is not possible: +``` +const rootReducer = combineReducers({ + a : reducerA, + b : { + b1 : reducerB1, + b2 : reducerB2 + } +}); +``` +- reducers within combineReducers are only passed the part of the state that they modify, and not the top state. + +The default utility combineReducers is only one way to build a complex reducer. Consider using libraries like [combineSectionReducers](https://github.com/ryo33/combine-section-reducers) or [reduceReducers](https://github.com/acdlite/reduce-reducers) if you want your reducers to have a nested tree structure. + + +### Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()? +In general, connect provides some way to generate a props object out of a closure that is injected with both the current state and dispatch. Asynchronous logic does not belong in the mapStateToProps and mapDispatchToProps functions at all. They should be only pure functions which transform the state to props and bind action creators to dispatch. + +You cannot modify the state during the execution of mapStateToProps, because modifying the state from these functions could lead to infinite loops because every update would reinvoke the map functions. Calling getState() inside mapStateToProps would always just return the same state that is passed to the function. + +The designed way to handle this use-case (needing to alter props based on the current state and mapDispatchToProps functions) is to work from the third argument to the connect function, mergeProps. If specified, it is passed the result of mapStateToProps(), mapDispatchToProps(), and the container component's props. The plain object you return from it will be passed as props to the wrapped component. + +#### Further information +**Discussions** +* [#580: Why doesn't Redux pass the state to subscribers?](https://github.com/reactjs/redux/issues/580) +* [#2214: Alternate Proof of Concept: Enhancer Overhaul -- more on debouncing](https://github.com/reactjs/redux/pull/2214) + +* [#1171: Why doesn't Redux use classes for actions and reducers?](https://github.com/reactjs/redux/issues/1171#issuecomment-196819727) +* Why does the middleware signature use currying? + * See - [#55](https://github.com/reactjs/redux/pull/55), [#534](https://github.com/reactjs/redux/issues/534), [#784](https://github.com/reactjs/redux/pull/784), [#922](https://github.com/reactjs/redux/issues/922), [#1744](https://github.com/reactjs/redux/issues/1744) +* Why does applyMiddleware use a closure for dispatch? + * See - [#1592](https://github.com/reactjs/redux/pull/1592) and [#2097](https://github.com/reactjs/redux/issues/2097) +* [#1768 Can you please change combineReducers to support nested state trees?](https://github.com/reactjs/redux/pull/1768) +* [#237 Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()?](https://github.com/reactjs/react-redux/issues/237) From a71d9182e5ca871150e0b69cb3fe61906730b3bb Mon Sep 17 00:00:00 2001 From: sbakkila Date: Mon, 24 Jul 2017 20:45:26 -0400 Subject: [PATCH 2/5] Update DesignDecisions.md --- docs/faq/DesignDecisions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq/DesignDecisions.md b/docs/faq/DesignDecisions.md index 1f96388c2f..f2e4af07a5 100644 --- a/docs/faq/DesignDecisions.md +++ b/docs/faq/DesignDecisions.md @@ -14,7 +14,7 @@ ### Why doesn't Redux pass the state and action to subscribers? -Subscribers are intended to respond to the state value itself, not the action. Updates to the state are not always processed synchronously, because Redux sometimes processes actions in batches to optimize performance and repeated re-rendering. The intended guarantee is that Redux eventually calls all subscribers with the most recent state, but not that it always calls each subscriber for each action. The store state is available in the subscriber simply by calling store.getState(). The action cannot be made available in the subsribers without breaking the way that actions are batched. +Subscribers are intended to respond to the state value itself, not the action. Updates to the state are not always processed synchronously, because libraries can change Redux to process actions in batches to optimize performance and avoid repeated re-rendering. The intended guarantee is that Redux eventually calls all subscribers with the most recent state, but not that it always calls each subscriber for each action. The store state is available in the subscriber simply by calling store.getState(). The action cannot be made available in the subsribers without breaking the way that actions are batched. A potential use-case for using the action inside a subscriber -- which is an unsupported feature -- is to ensure that a component only re-renders after certain kinds of actions. Re-rendering should instead be controlled instead through: 1.) the [shouldComponentUpdate](https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate) lifecycle method From aad27f5925a63ca967b5bee0c53b4ffd360f5c60 Mon Sep 17 00:00:00 2001 From: sbakkila Date: Mon, 24 Jul 2017 21:23:31 -0400 Subject: [PATCH 3/5] fix small typos --- docs/faq/DesignDecisions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/faq/DesignDecisions.md b/docs/faq/DesignDecisions.md index f2e4af07a5..b1477b3f8e 100644 --- a/docs/faq/DesignDecisions.md +++ b/docs/faq/DesignDecisions.md @@ -55,11 +55,11 @@ The default utility combineReducers is only one way to build a complex reducer. ### Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()? -In general, connect provides some way to generate a props object out of a closure that is injected with both the current state and dispatch. Asynchronous logic does not belong in the mapStateToProps and mapDispatchToProps functions at all. They should be only pure functions which transform the state to props and bind action creators to dispatch. +In general, connect generates a props object out of a closure that is injected with both the current state and dispatch. Asynchronous logic does not belong in the mapStateToProps and mapDispatchToProps functions at all. They should be only pure functions which transform the state to props and bind action creators to dispatch. -You cannot modify the state during the execution of mapStateToProps, because modifying the state from these functions could lead to infinite loops because every update would reinvoke the map functions. Calling getState() inside mapStateToProps would always just return the same state that is passed to the function. +You cannot modify the state during the execution of mapStateToProps. Modifying the state from these functions could lead to infinite loops because every update would reinvoke the map functions. Calling getState inside mapStateToProps would always just return the same state that is passed to the function. -The designed way to handle this use-case (needing to alter props based on the current state and mapDispatchToProps functions) is to work from the third argument to the connect function, mergeProps. If specified, it is passed the result of mapStateToProps(), mapDispatchToProps(), and the container component's props. The plain object you return from it will be passed as props to the wrapped component. +The preferred way to handle this use-case (needing to alter props based on the current state and mapDispatchToProps functions) is to work from mergeProps, the third argument to the connect function. If specified, it is passed the result of mapStateToProps(), mapDispatchToProps(), and the container component's props. The plain object returned from mergeProps will be passed as props to the wrapped component. #### Further information **Discussions** From 5bf622f05e2c588a14145ba508c38c0800c350ed Mon Sep 17 00:00:00 2001 From: Sam Bakkila Date: Mon, 7 Aug 2017 13:02:33 -0400 Subject: [PATCH 4/5] fix: DesignDecision FAQ edits based on feedback --- docs/FAQ.md | 4 +- docs/faq/DesignDecisions.md | 100 ++++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 40 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index c45840e3c6..97b8fcd456 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -48,8 +48,8 @@ - [Why doesn't Redux support using classes for actions and reducers?](/docs/faq/DesignDecisions.md#does-not-support-classes) - [Why does the middleware signature use currying?](/docs/faq/DesignDecisions.md#why-currying) - [Why does applyMiddleware use a closure for dispatch?](/docs/faq/DesignDecisions.md#closure-dispatch) - - [Can you please change combineReducers to support nested state trees?](/docs/faq/DesignDecisions.md#combineReducers-limitations) - - [Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()?](/docs/faq/DesignDecisions.md#no-asynch-in-mapDispatchToProps) + - [Why doesn't `combineReducers` include a third argument with the entire state when it calls each reducer?](/docs/faq/DesignDecisions.md#combineReducers-limitations) + - [Why doesn't `mapDispatchToProps` allow use of return values from `getState()` or `mapStateToProps()`?](/docs/faq/DesignDecisions.md#no-asynch-in-mapDispatchToProps) - **React Redux** - [Why isn't my component re-rendering, or my mapStateToProps running?](/docs/faq/ReactRedux.md#react-not-rerendering) - [Why is my component re-rendering too often?](/docs/faq/ReactRedux.md#react-rendering-too-often) diff --git a/docs/faq/DesignDecisions.md b/docs/faq/DesignDecisions.md index b1477b3f8e..c8590376f2 100644 --- a/docs/faq/DesignDecisions.md +++ b/docs/faq/DesignDecisions.md @@ -6,70 +6,94 @@ - [Why doesn't Redux support using classes for actions and reducers?](#does-not-support-classes) - [Why does the middleware signature use currying?](#why-currying) - [Why does applyMiddleware use a closure for dispatch?](#closure-dispatch) -- [Can you please change combineReducers to support nested state trees?](#combineReducers-limitations) -- [Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()?](#no-asynch-in-mapDispatchToProps) +- [Why doesn't `combineReducers` include a third argument with the entire state when it calls each reducer?](#combineReducers-limitations) +- [Why doesn't mapDispatchToProps allow use of return values from `getState()` or `mapStateToProps()`?](#no-asynch-in-mapDispatchToProps) ## Design Decisions ### Why doesn't Redux pass the state and action to subscribers? -Subscribers are intended to respond to the state value itself, not the action. Updates to the state are not always processed synchronously, because libraries can change Redux to process actions in batches to optimize performance and avoid repeated re-rendering. The intended guarantee is that Redux eventually calls all subscribers with the most recent state, but not that it always calls each subscriber for each action. The store state is available in the subscriber simply by calling store.getState(). The action cannot be made available in the subsribers without breaking the way that actions are batched. +Subscribers are intended to respond to the state value itself, not the action. Updates to the state processed synchronously, but notifications to subscribers are batched or debounced, meaning that subscribers are not always notified with every action. This is a common [performance optimization](http://redux.js.org/docs/faq/Performance.html#performance-update-events) to avoid repeated re-rendering. + +Batching or debouncing is possible by using enhancers to override `store.dispatch` to change the way that subscribers are notified. Also, there are libraries that change Redux to process actions in batches to optimize performance and avoid repeated re-rendering: +* [redux-batch](https://github.com/manaflair/redux-batch) allows passing an array of actions to `store.dispatch()` with only one notification, +* [redux-batched-subscribe](https://github.com/tappleby/redux-batched-subscribe) allows batching of subscribe notifications that occur as a result of dispatches. + +The intended guarantee is that Redux eventually calls all subscribers with the most recent state, but not that it always calls each subscriber for each action. The store state is available in the subscriber simply by calling `store.getState()`. The action cannot be made available in the subscribers without breaking the way that actions are batched. A potential use-case for using the action inside a subscriber -- which is an unsupported feature -- is to ensure that a component only re-renders after certain kinds of actions. Re-rendering should instead be controlled instead through: -1.) the [shouldComponentUpdate](https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate) lifecycle method -2.) the [virtual DOM equality check (vDOMEq)](https://facebook.github.io/react/docs/optimizing-performance.html#avoid-reconciliation) -3.) [React.PureComponent](https://facebook.github.io/react/docs/optimizing-performance.html#examples) -4.) Using React-Redux: use [mapStateToProps](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) to subscribe components to only the parts of the store that they need. +1. the [shouldComponentUpdate](https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate) lifecycle method +2. the [virtual DOM equality check (vDOMEq)](https://facebook.github.io/react/docs/optimizing-performance.html#avoid-reconciliation) +3. [React.PureComponent](https://facebook.github.io/react/docs/optimizing-performance.html#examples) +4. Using React-Redux: use [mapStateToProps](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) to subscribe components to only the parts of the store that they need. + +#### Further Information +**Articles** + * [How can I reduce the number of store update events?](./Performance.md#performance-update-events) + +**Discussions** +* [#580: Why doesn't Redux pass the state to subscribers?](https://github.com/reactjs/redux/issues/580) +* [#2214: Alternate Proof of Concept: Enhancer Overhaul -- more on debouncing](https://github.com/reactjs/redux/pull/2214) ### Why doesn't Redux support using classes for actions and reducers? -The pattern of using functions, called action creators, to return action objects may seem counterintuitive to programmers with a lot of Object Oriented Programming experience, who would see this is a strong use-case for Classes and instances. Class instances for action objects and reducers are not supported because class instances make serialization and deserialization tricky. Deserialization methods like JSON.parse(string) will return a plain old Javascript object rather than class instances. +The pattern of using functions, called action creators, to return action objects may seem counterintuitive to programmers with a lot of Object Oriented Programming experience, who would see this is a strong use-case for Classes and instances. Class instances for action objects and reducers are not supported because class instances make serialization and deserialization tricky. Deserialization methods like `JSON.parse(string)` will return a plain old Javascript object rather than class instances. + +As described in the [Store FAQ](./OrganizingState.md#organizing-state-non-serializable), if you are okay with things like persistence and time-travel debugging not working as intended, you are welcome to put non-serializable items into your Redux store. Serialization enables the brower to store all actions that have been dispatched, as well as the previous store states, with much less memory. Rewinding and 'hot reloading' the store is central to the Redux developer experience and the function of Redux DevTools. This also enables deserialized actions to be stored on the server and re-serialized in the brower in the case of server-side rendering with Redux. +#### Further Information +**Articles** +* [Can I put functions, promises, or other non-serializable items in my store state?](./OrganizingState.md#organizing-state-non-serializable) + +**Discussions** +* [#1171: Why doesn't Redux use classes for actions and reducers?](https://github.com/reactjs/redux/issues/1171#issuecomment-196819727) + ### Why does the middleware signature use currying? The [curried function signature](https://github.com/reactjs/redux/issues/1744) of declaring middleware is [deemed unnecessary](https://github.com/reactjs/redux/pull/784) by some, because both store and next are available when the applyMiddleware function is executed. This issue has been determined to not be [worth introducing breaking changes](https://github.com/reactjs/redux/issues/1744). +#### Further Information +**Discussions** +* Why does the middleware signature use currying? + * See - [#55](https://github.com/reactjs/redux/pull/55), [#534](https://github.com/reactjs/redux/issues/534), [#784](https://github.com/reactjs/redux/pull/784), [#922](https://github.com/reactjs/redux/issues/922), [#1744](https://github.com/reactjs/redux/issues/1744) + -### Why does applyMiddleware use a closure for dispatch? -applyMiddleware takes the existing dispatch from the store and closes over it to create the initial chain of middlewares that have been invoked with an object that exposes the getState and dispatch functions, which enables middlewares that [rely on dispatch during initialization](https://github.com/reactjs/redux/pull/1592) to run. +### Why does `applyMiddleware` use a closure for `dispatch`? +`applyMiddleware` takes the existing dispatch from the store and closes over it to create the initial chain of middlewares that have been invoked with an object that exposes the getState and dispatch functions, which enables middlewares that [rely on dispatch during initialization](https://github.com/reactjs/redux/pull/1592) to run. + +#### Further Information +**Discussions** +* Why does applyMiddleware use a closure for dispatch? + * See - [#1592](https://github.com/reactjs/redux/pull/1592) and [#2097](https://github.com/reactjs/redux/issues/2097) -### Can you please change combineReducers to support nested state trees? -No, but there are some limits to combineReducers that are worth knowing. -- combineReducers receives an object where the values are all reducer names. Additional nesting is not possible, which limits the state shape. The following code is not possible: -``` -const rootReducer = combineReducers({ - a : reducerA, - b : { - b1 : reducerB1, - b2 : reducerB2 - } -}); -``` -- reducers within combineReducers are only passed the part of the state that they modify, and not the top state. - -The default utility combineReducers is only one way to build a complex reducer. Consider using libraries like [combineSectionReducers](https://github.com/ryo33/combine-section-reducers) or [reduceReducers](https://github.com/acdlite/reduce-reducers) if you want your reducers to have a nested tree structure. +### Why doesn't `combineReducers` include a third argument with the entire state when it calls each reducer? - -### Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()? -In general, connect generates a props object out of a closure that is injected with both the current state and dispatch. Asynchronous logic does not belong in the mapStateToProps and mapDispatchToProps functions at all. They should be only pure functions which transform the state to props and bind action creators to dispatch. +`combineReducers` is deliberately opinionated to encourage splitting reducer logic by domain. As stated in [Beyond `combineReducers`](../recipes/reducers/BeyondCombineReducers.md),`combineReducers` is deliberately limited to handle a single common use case: updating a state tree that is a plain Javascript object by delegating the work of updating each slice of state to a specific slice reducer. -You cannot modify the state during the execution of mapStateToProps. Modifying the state from these functions could lead to infinite loops because every update would reinvoke the map functions. Calling getState inside mapStateToProps would always just return the same state that is passed to the function. +It's not immediately obvious what a potential third argument should be: the entire state tree, some callback function, some other part of the state tree, etc. If `combineReducers` doesn't fit your use case, consider using libraries like [combineSectionReducers](https://github.com/ryo33/combine-section-reducers) or [reduceReducers](https://github.com/acdlite/reduce-reducers) for other options with deeply nested reducers and reducers that require access to the global state. -The preferred way to handle this use-case (needing to alter props based on the current state and mapDispatchToProps functions) is to work from mergeProps, the third argument to the connect function. If specified, it is passed the result of mapStateToProps(), mapDispatchToProps(), and the container component's props. The plain object returned from mergeProps will be passed as props to the wrapped component. +If none of the published utilities solve your use case, you can always write a function yourself that does just exactly what you need. #### Further information +**Articles** +* [Beyond `combineReducers`](../recipes/reducers/BeyondCombineReducers.md) + **Discussions** -* [#580: Why doesn't Redux pass the state to subscribers?](https://github.com/reactjs/redux/issues/580) -* [#2214: Alternate Proof of Concept: Enhancer Overhaul -- more on debouncing](https://github.com/reactjs/redux/pull/2214) +* [#1768 Allow reducers to consult global state](https://github.com/reactjs/redux/pull/1768) -* [#1171: Why doesn't Redux use classes for actions and reducers?](https://github.com/reactjs/redux/issues/1171#issuecomment-196819727) -* Why does the middleware signature use currying? - * See - [#55](https://github.com/reactjs/redux/pull/55), [#534](https://github.com/reactjs/redux/issues/534), [#784](https://github.com/reactjs/redux/pull/784), [#922](https://github.com/reactjs/redux/issues/922), [#1744](https://github.com/reactjs/redux/issues/1744) -* Why does applyMiddleware use a closure for dispatch? - * See - [#1592](https://github.com/reactjs/redux/pull/1592) and [#2097](https://github.com/reactjs/redux/issues/2097) -* [#1768 Can you please change combineReducers to support nested state trees?](https://github.com/reactjs/redux/pull/1768) + +### Why doesn't `mapDispatchToProps` allow use of return values from `getState()` or `mapStateToProps()`? + +There have been requests to use either the entire `state` or the return value of `mapState` inside of `mapDispatch`, so that when functions are declared inside of `mapDispatch`, they can close over the latest returned values from the store. + +This approach is not supported in `mapDispatch` because it would mean also calling `mapDispatch` every time the store is updated. This would cause the re-creation of functions with every state update, thus adding a lot of performance overhead. + +The preferred way to handle this use-case--needing to alter props based on the current state and mapDispatchToProps functions--is to work from mergeProps, the third argument to the connect function. If specified, it is passed the result of `mapStateToProps()`, `mapDispatchToProps()`, and the container component's props. The plain object returned from `mergeProps` will be passed as props to the wrapped component. + +#### Further information +**Discussions** * [#237 Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()?](https://github.com/reactjs/react-redux/issues/237) From 0b496c2c0385126c43143469367e63f38e168048 Mon Sep 17 00:00:00 2001 From: Sam Bakkila Date: Mon, 7 Aug 2017 15:37:21 -0400 Subject: [PATCH 5/5] fix: small changes to combineReducers question in DesignDecisions.md --- docs/faq/DesignDecisions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/faq/DesignDecisions.md b/docs/faq/DesignDecisions.md index c8590376f2..91393a517d 100644 --- a/docs/faq/DesignDecisions.md +++ b/docs/faq/DesignDecisions.md @@ -72,9 +72,9 @@ The [curried function signature](https://github.com/reactjs/redux/issues/1744) o ### Why doesn't `combineReducers` include a third argument with the entire state when it calls each reducer? -`combineReducers` is deliberately opinionated to encourage splitting reducer logic by domain. As stated in [Beyond `combineReducers`](../recipes/reducers/BeyondCombineReducers.md),`combineReducers` is deliberately limited to handle a single common use case: updating a state tree that is a plain Javascript object by delegating the work of updating each slice of state to a specific slice reducer. +`combineReducers` is opinionated to encourage splitting reducer logic by domain. As stated in [Beyond `combineReducers`](../recipes/reducers/BeyondCombineReducers.md),`combineReducers` is deliberately limited to handle a single common use case: updating a state tree that is a plain Javascript object by delegating the work of updating each slice of state to a specific slice reducer. -It's not immediately obvious what a potential third argument should be: the entire state tree, some callback function, some other part of the state tree, etc. If `combineReducers` doesn't fit your use case, consider using libraries like [combineSectionReducers](https://github.com/ryo33/combine-section-reducers) or [reduceReducers](https://github.com/acdlite/reduce-reducers) for other options with deeply nested reducers and reducers that require access to the global state. +It's not immediately obvious what a potential third argument to each reducer should be: the entire state tree, some callback function, some other part of the state tree, etc. If `combineReducers` doesn't fit your use case, consider using libraries like [combineSectionReducers](https://github.com/ryo33/combine-section-reducers) or [reduceReducers](https://github.com/acdlite/reduce-reducers) for other options with deeply nested reducers and reducers that require access to the global state. If none of the published utilities solve your use case, you can always write a function yourself that does just exactly what you need.