it-swarm.dev

Redux bersarang bersarang

Apakah mungkin untuk menggabungkan reduksi yang bersarang dengan struktur berikut:

import 'user' from ...
import 'organisation' from ...
import 'auth' from ...
// ...

export default combineReducers({
  auth: {
    combineReducers({
        user,
        organisation,  
    }),
    auth,
  },
  posts,
  pages,
  widgets,
  // .. more state here
});

Di mana negara memiliki struktur:

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

Di mana peredam auth memiliki struktur:

{
    token: 123123123,
    cypher: '256',
    someKey: 123,   
}

jadi mungkin operator spread berguna? ...auth tidak yakin :-(

42
AndrewMcLagan

Tidak apa-apa untuk menggabungkan pengurang bersarang Anda menggunakan combineReducers. Tetapi ada pola lain yang sangat berguna: reducer bersarang.

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

Dalam contoh di atas, authReducer dapat meneruskan tindakan ke organisationReducer dan userReducer untuk memperbarui beberapa bagian dari keadaannya.

54
Florent

Hanya ingin menguraikan sedikit tentang jawaban yang sangat bagus @Florent memberi dan menunjukkan bahwa Anda juga dapat menyusun aplikasi Anda sedikit berbeda untuk mencapai reducer bersarang, dengan meminta root reducer Anda digabungkan dari reducer yang juga merupakan reduksi gabungan

Sebagai contoh

// 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
});

ini mengasumsikan sedikit berbeda dari struktur negara. Sebaliknya, seperti:

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

@ Pendekatan Florent kemungkinan akan lebih baik jika Anda tidak dapat mengubah struktur negara

33
Joseph Nields

Terinspirasi oleh @ florent's answer, saya menemukan Anda juga bisa mencoba ini. Belum tentu lebih baik daripada jawabannya, tetapi saya pikir itu sedikit lebih elegan.

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)}
  }
}
4
D.W

Contoh (lihat attachNestedReducers di bawah)

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

Nyatakan objek 

{
    some: 'state',
    profile: { /* ... */ }
}

Inilah fungsinya

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
  }
}
0
Andrew Luca