2016-03-11 22 views
21

Próbuję zawinąć głowę, jak zmienić stan głęboko zagnieżdżony w redux. To ma sens, aby połączyć te reduktory i zmienić właściwości pierwszego poziomu dla tych elementów. Gdzie nie jestem tak jasne, jak zmienić stan głęboko zagnieżdżonej nieruchomości. Załóżmy, że mam aplikację na zakupy. Poniżej jest mój stan:Redukcje Redux - zmiana stanu głęboko zagnieżdżonego

{ 
    cart: { 
     items: [] 
    }, 
    account: { 
     amountLeft: 100, 
     discounts: { 
     redeemed: [], 
     coupons: { 
      buyOneGetOne: false 
     } 
     } 
    } 
} 

Gdy użytkownik wchodzi w kodzie, powiedzmy, że można je odkupić „buyOneGetOne” kupon i wartość ta powinna stać się prawdą. Mam reduktor do koszyka i inny na konto. Dla nieruchomości na pierwszym poziomie (jak gdybym był wybić koszyk w pozycji), chciałbym po prostu wykonaj następujące czynności w moim reduktora:

case 'EMPTY_CART': 
    return Object.assign({}, state, {items: []}); 

na zmianę buyOneGetOne, jednak wydaje się, że ja najpierw trzeba zrobić Object.assign na kuponach (ponieważ buyOneGetOne został zmodyfikowany), a następnie robi Object.assign na rabatach (ponieważ miałem zmodyfikowane kupony), a następnie ostatecznie emitując akcję, aby reduktor mógł zrobić Object.assign na koncie (ponieważ rabaty teraz zmienione). Wydaje się to jednak bardzo skomplikowane i łatwe do wykonania, co prowadzi do przekonania, że ​​musi istnieć lepszy sposób.

Czy to wszystko źle? Wygląda na to, że reduktory są używane tylko do modyfikowania właściwości poziomu głównego stanu (takich jak koszyk i konto) i że nie powinienem mieć reduktora, który dotyka stanu wewnątrz konta (jak reduktor zniżek), ponieważ konto ma już reduktor . Ale gdy chcę tylko zmienić jedną właściwość daleko w dół drzewa stanu, scalenie każdego obiektu od tej zmiany aż do łańcucha obiektu do dziecka korzenia staje się skomplikowane ...

Czy możesz/możesz mieć reduktory wewnątrz reduktorów, jak w tym przypadku masz reduktor zniżek?

Odpowiedz

25

Z pewnością w reduktorach można mieć reduktory; w rzeczywistości aplikacja demo redux robi to: http://redux.js.org/docs/basics/Reducers.html.

Na przykład, można zrobić zagnieżdżony reduktor nazwie `rabaty:

function discounts(state, action) { 
    switch (action.type) { 
     case ADD_DISCOUNT: 
      return state.concat([action.payload]); 

     // etc etc 
    } 
} 

A następnie skorzystać z tego reduktora w reduktor obrotów:

function account(state, action) { 
    switch (action.type) { 
     case ADD_DISCOUNT: 
      return { 
       ...state, 
       discounts: discounts(state.discounts, action) 
      }; 

     // etc etc 
    } 
} 

Aby dowiedzieć więcej, sprawdź kod egghead.io redux series autorstwa samego Dana, a konkretnie wideo o numerze reducer composition!

+1

Cholera, pokonaj mnie kilka sekund - świetna odpowiedź! – mxstbr

+7

W rzeczywistości możesz użyć 'combineReducers()' więcej niż jeden raz w swojej aplikacji. Polecam wypróbowanie przykładu [shopping-cart] (https://github.com/reactjs/redux/tree/master/examples/shopping-cart/reducers) w repozytorium Redux, które demonstruje różne schematy składu reduktora. –

+3

To fajne, nie zdawałem sobie z tego sprawy. Jednak nie jest celem, aby mieć tak płaskie drzewo stanu, jak to możliwe? Gdzie jest równowaga między zagnieżdżonymi reduktorami a drzewem o płaskim stanie? – Skitterm

3

zalecana gniazdo combinedReducers dla każdego poziomu głębokiego

0

Tak, oddzielając te reduktory jest słuszne. Właściwie, jeśli obawiasz się, że niektóre z tych działań będą wymagały zmiany innego reduktora, możesz albo zareagować na inną stałą, albo po prostu wysłać kolejną akcję.

w celu rozwiązania tego problemu - aby umożliwić łatwą kompozycję i uniknąć szczegółowej składni wraz z połączeniem wyniku. Tak, Twój przykład wygląda tak:

import { createTile, createSyncTile } from 'redux-tiles'; 

const cartItems = createSyncTile({ 
    type: ['account', 'cart'], 
    fn: ({ params }) => ({ items: params.items }) 
}); 

const coupons = createSyncTile({ 
    type: ['account', 'coupons'], 
    fn: ({ params }) => params, 
}); 

const reedemedCoupons = createSyncTile({ 
    type: ['account', 'reedemedCoupons'], 
    fn: ({ params }) => params.coupons 
}); 

const account = createTile({ 
    type: ['account', 'info'], 
    fn: ({ api }) => api.get('/client/info') 
}); 

Stosując tę ​​strategię każdy składnik jest atomowy, i można łatwo tworzyć nowe i wysyłkowe innych, bez wpływu na innych, to sprawia, że ​​łatwiej byłaby i usunąć niektóre funkcje w przyszłość, kiedy twoje "kafle" przestrzegają zasady jednej odpowiedzialności.

Powiązane problemy