Javascript 嵌套的 redux 减速器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36786244/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Nested redux reducers
提问by AndrewMcLagan
Is it possible to combine reducers that are nested with the following structure:
是否可以组合使用以下结构嵌套的减速器:
import 'user' from ...
import 'organisation' from ...
import 'auth' from ...
// ...
export default combineReducers({
auth: {
combineReducers({
user,
organisation,
}),
auth,
},
posts,
pages,
widgets,
// .. more state here
});
Where the state has the structure:
状态具有以下结构的地方:
{
auth: {
user: {
firstName: 'Foo',
lastName: 'bar',
}
organisation: {
name: 'Foo Bar Co.'
phone: '1800-123-123',
},
token: 123123123,
cypher: '256',
someKey: 123,
}
}
Where the authreducer has the structure:
其中auth减速机具有以下结构:
{
token: 123123123,
cypher: '256',
someKey: 123,
}
so maybe the spread operator is handy? ...authnot sure :-(
所以也许传播运算符很方便?...auth没有把握 :-(
回答by Florent
It is perfectly fine to combine your nested reducers using combineReducers. But there is another pattern which is really handy: nested reducers.
使用combineReducers. 但是还有另一种模式非常方便:嵌套减速器。
const initialState = {
user: null,
organisation: null,
token: null,
cypher: null,
someKey: null,
}
function authReducer(state = initialState, action) {
switch (action.type) {
case SET_ORGANISATION:
return {...state, organisation: organisationReducer(state.organisation, action)}
case SET_USER:
return {...state, user: userReducer(state.user, action)}
case SET_TOKEN:
return {...state, token: action.token}
default:
return state
}
}
In the above example, the authReducercan forward the action to organisationReducerand userReducerto update some part of its state.
在上面的示例中,authReducer可以将操作转发到organisationReducer并userReducer更新其状态的某些部分。
回答by Joseph Nields
Just wanted to elaborate a bit on the very good answer @Florent gave and point out that you can also structure your app a bit differently to achieve nested reducers, by having your root reducer be combined from reducers that are also combined reducers
只是想详细说明@Florent 给出的非常好的答案,并指出您还可以通过将您的根减速器与也是组合减速器的减速器组合来稍微不同地构建您的应用程序以实现嵌套减速器
For example
例如
// src/reducers/index.js
import { combineReducers } from "redux";
import auth from "./auth";
import posts from "./posts";
import pages from "./pages";
import widgets from "./widgets";
export default combineReducers({
auth,
posts,
pages,
widgets
});
// src/reducers/auth/index.js
// note src/reducers/auth is instead a directory
import { combineReducers } from "redux";
import organization from "./organization";
import user from "./user";
import security from "./security";
export default combineReducers({
user,
organization,
security
});
this assumes a bit different of a state structure. Instead, like so:
这假设了一个有点不同的状态结构。相反,像这样:
{
auth: {
user: {
firstName: 'Foo',
lastName: 'bar',
}
organisation: {
name: 'Foo Bar Co.'
phone: '1800-123-123',
},
security: {
token: 123123123,
cypher: '256',
someKey: 123
}
},
...
}
@Florent's approach would likely be better if you're unable to change the state structure, however
但是,如果您无法更改状态结构,@Florent 的方法可能会更好
回答by D.W
Inspired by @florent'sanswer, I found that you could also try this. Not necessarily better than his answer, but i think it's a bit more elegant.
受到@ florent'sanswer的启发,我发现你也可以试试这个。不一定比他的回答好,但我认为它更优雅一些。
function userReducer(state={}, action) {
switch (action.type) {
case SET_USERNAME:
state.name = action.name;
return state;
default:
return state;
}
}
function authReducer(state = {
token: null,
cypher: null,
someKey: null,
}, action) {
switch (action.type) {
case SET_TOKEN:
return {...state, token: action.token}
default:
// note: since state doesn't have "user",
// so it will return undefined when you access it.
// this will allow you to use default value from actually reducer.
return {...state, user: userReducer(state.user, action)}
}
}
回答by Andrew Luca
Example (see attachNestedReducersbellow)
示例(见下文attachNestedReducers)
import { attachNestedReducers } from './utils'
import { profileReducer } from './profile.reducer'
const initialState = { some: 'state' }
const userReducerFn = (state = initialState, action) => {
switch (action.type) {
default:
return state
}
}
export const userReducer = attachNestedReducers(userReducerFn, {
profile: profileReducer,
})
State object
状态对象
{
some: 'state',
profile: { /* ... */ }
}
Here is the function
这是函数
export function attachNestedReducers(original, reducers) {
const nestedReducerKeys = Object.keys(reducers)
return function combination(state, action) {
const nextState = original(state, action)
let hasChanged = false
const nestedState = {}
for (let i = 0; i < nestedReducerKeys.length; i++) {
const key = nestedReducerKeys[i]
const reducer = reducers[key]
const previousStateForKey = nextState[key]
const nextStateForKey = reducer(previousStateForKey, action)
nestedState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? Object.assign({}, nextState, nestedState) : nextState
}
}

