-
-
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
Allow combineReducers reducers to consult global state #2750
Comments
This is related to #1768, which was abandoned. |
I know that Dan's opinion on this is that |
I think that this may break boundaries of redux state — you may do this itself but you should not request this from this library… |
Here's a typesafe version I wrote for typescript 2.8: type FunctionReturnType<T> = T extends (...args: any[]) => infer R ? R : never
type CombinedState<T extends object> = { [K in keyof T]: FunctionReturnType<T[K]> }
type ActionFromReducer<T extends object> = T[keyof T] extends (
state: any,
action: infer A,
...args: any[]
) => any
? A
: never
type ReducerReturnValue<T extends object, R> = (
state: CombinedState<T>,
action: ActionFromReducer<T>,
rootState: R,
) => CombinedState<T>
// TODO: remove inner function, see:
// * https://github.com/Microsoft/TypeScript/issues/20122
// * https://github.com/Microsoft/TypeScript/pull/23696
export function combineReducers<R>() {
return <T extends object>(reducers: T): ReducerReturnValue<T, R> => {
type S = CombinedState<T>
const reducerProps = Object.keys(reducers)
return (state: S = {} as S, action: any, rootState: R): S => {
let hasChanged = false
const nextState: S = {} as S
for (let i = 0; i < reducerProps.length; ++i) {
const prop = reducerProps[i]
const reducer = reducers[prop]
const previousStateForKey = state[prop]
const nextStateForKey = reducer(previousStateForKey, action, rootState)
nextState[prop] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
}
}
}
type ReducerReturnValueRoot<T extends object> = (
state: CombinedState<T>,
action: ActionFromReducer<T>,
) => CombinedState<T>
export function combineReducersRoot<T extends object>(reducers: T): ReducerReturnValueRoot<T> {
type S = CombinedState<T>
const reducerProps = Object.keys(reducers)
return (state: S = {} as S, action: any): S => {
let hasChanged = false
const nextState: S = {} as S
for (let i = 0; i < reducerProps.length; ++i) {
const prop = reducerProps[i]
const reducer = reducers[prop]
const previousStateForKey = state[prop]
const nextStateForKey = reducer(previousStateForKey, action, state)
nextState[prop] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
}
} You have to use |
Why not pass the global state as an argument to the reducers? I created a PR (#3010) to show example. |
Still a nice idea, but realistically, this isn't going to happen at this point. |
Do you want to request a feature or report a bug?
feature
What is the current behavior?
The subreducers of combineReducers are real reducers, they only get
state
andaction
, it would be nice if we could pass an extra argument to these reducers through an option, e.g. to inject the full state back into the subreducers if a reducer might need some information of another reducer without ever needing to change it.I know we can write this ourselves, however, we wouldn't get all the warnings and/or optimizations of combineReducers then.
e.g.
The text was updated successfully, but these errors were encountered: