70 votes

Réducteurs imbriqués

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 :-(

78voto

Florent Points 6599

Il est parfaitement approprié de combiner vos réducteurs imbriqués avec combineReducers . Mais il existe un autre modèle très 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, les authReducer peuvent transférer l'action à organisationReducer et userReducer pour mettre à jour une partie de son état.

57voto

Joseph Nields Points 2459

Voulais juste développer un peu sur la très bonne réponse @Florent a donné un point que vous pouvez également la structure de votre application un peu différemment pour obtenir imbriquée réducteurs, en ayant la racine de votre réducteur être combinés à partir de réducteurs qui sont également combinées de réducteurs

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 ceci:

{
    auth: {
        user: {
            firstName: 'Foo',
            lastName: 'bar',
        }
        organisation: {
            name: 'Foo Bar Co.'
            phone: '1800-123-123',
        },
        security: {
            token: 123123123,
            cypher: '256',
            someKey: 123
        }
    },
    ...
}

@Florent l'approche serait probablement mieux si vous n'êtes pas en mesure de modifier la structure de l'état, cependant

11voto

D.W Points 61

Inspiré par la réponse de @ florent , j'ai trouvé que vous pouviez également 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)}
  }
}
 

2voto

Andrew Luca Points 1168

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
  }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X