Est-il possible de combiner des réducteurs imbriqués avec la structure suivante:
import 'user' from ...
import 'organisation' from ...
import 'auth' from ...
// ...
export default combineReducers({
auth: {
combineReducers({
user,
organisation,
}),
auth,
},
posts,
pages,
widgets,
// .. more state here
});
Où l'état a la structure:
{
auth: {
user: {
firstName: 'Foo',
lastName: 'bar',
}
organisation: {
name: 'Foo Bar Co.'
phone: '1800-123-123',
},
token: 123123123,
cypher: '256',
someKey: 123,
}
}
Où le réducteur auth
a la structure:
{
token: 123123123,
cypher: '256',
someKey: 123,
}
alors peut-être que l'opérateur de propagation est pratique? ...auth
pas sûr :-(
Il est parfaitement judicieux de combiner vos réducteurs imbriqués en utilisant combineReducers
. Mais il existe un autre modèle qui est vraiment pratique: les réducteurs imbriqués.
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
}
}
Dans l'exemple ci-dessus, authReducer
peut transmettre l'action à organisationReducer
et userReducer
afin de mettre à jour une partie de son état.
Je voulais juste élaborer un peu sur la très bonne réponse donnée par @Florent et souligner que vous pouvez également structurer votre application un peu différemment pour obtenir des réducteurs imbriqués, en associant votre réducteur de racine à des réducteurs qui sont également des réducteurs combinés
Par exemple
// 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
});
cela suppose un peu différent d'une structure d'état. Au lieu de cela, comme si:
{
auth: {
user: {
firstName: 'Foo',
lastName: 'bar',
}
organisation: {
name: 'Foo Bar Co.'
phone: '1800-123-123',
},
security: {
token: 123123123,
cypher: '256',
someKey: 123
}
},
...
}
L'approche de @ Florent serait probablement meilleure si vous êtes incapable de changer la structure de l'état,
Inspiré par @ florent's answer, j'ai découvert que vous pouviez aussi essayer ceci. Pas nécessairement mieux que sa réponse, mais je pense que c'est un peu plus élégant.
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)}
}
}
Exemple (voir attachNestedReducers
ci-dessous)
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,
})
Objet d'état
{
some: 'state',
profile: { /* ... */ }
}
Voici la fonction
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
}
}