2016-07-14 16 views
6

Pytanie:Redux: organizowanie pojemniki, elementy, działania i reduktory

Co jest najbardziej utrzymaniu i zalecane najlepsze praktyki organizowania kontenery, komponenty, działania i reduktory w dużej React/Redux aplikacji ?

Moja opinia:

Obecne trendy wydają się organizować zabezpieczeń Redux (działania, reduktory, sagi ...) wokół związanego komponentu kontenera. na przykład

/src 
    /components 
     /... 
    /contianers 
     /BookList 
      actions.js 
      constants.js 
      reducer.js 
      selectors.js 
      sagas.js 
      index.js 
     /BookSingle 
      actions.js 
      constants.js 
      reducer.js 
      selectors.js 
      sagas.js 
      index.js   
    app.js 
    routes.js 

Działa to świetnie! Chociaż wydaje się, że istnieje kilka problemów z tym projektem.

Zagadnienia:

Kiedy trzeba przejść actions, selectors lub sagas z innego pojemnika wydaje anty-wzór. Załóżmy, że mamy globalny kontener /App z reduktorem/stanem, który przechowuje informacje, których używamy w całej aplikacji, takie jak kategorie i wyliczenia. Opierając się na powyższym przykładzie, z drzewa państwowej:

{ 
    app: { 
     taxonomies: { 
      genres: [genre, genre, genre], 
      year: [year, year, year], 
      subject: [subject,subject,subject], 
     } 
    } 
    books: { 
     entities: { 
      books: [book, book, book, book], 
      chapters: [chapter, chapter, chapter], 
      authors: [author,author,author], 
     } 
    }, 
    book: { 
     entities: { 
      book: book, 
      chapters: [chapter, chapter, chapter], 
      author: author, 
     } 
    }, 
} 

Jeśli chcemy użyć selector z pojemnika /App w naszym /BookList pojemnika musimy albo odtworzyć go w /BookList/selectors.js (na pewno nie tak?) Lub zaimportować od /App/selectors (czy zawsze będzie to WYBÓR tego samego selektora ...? nie.). Obie te cechy wydają mi się nieoptymalne.

Podstawowym przykładem tego przypadku jest Uwierzytelnianie (ah ... auth, z którego lubimy cię nienawidzić), ponieważ jest to popularny "efekt uboczny". Często potrzebujemy uzyskać dostęp do sag, akcji i selektorów /Auth w całej aplikacji. Możemy mieć pojemniki /PasswordRecover, /PasswordReset, /Login, /Signup .... Właściwie w naszej aplikacji nasz /Auth contianer ma rzeczywisty komponent w ogóle!

/src 
    /contianers 
     /Auth 
      actions.js 
      constants.js 
      reducer.js 
      selectors.js 
      sagas.js 

Po prostu zawiera wszystkie zabezpieczenia Redux dla różnych i często niezwiązanych z nimi kontenerów auth, o których mowa powyżej.

+0

Jestem ciekawa, z aktualną strukturą, w jaki sposób używasz swojego selektora? Powiedzmy, że komponent używa funkcji selektora "BookList", czy możesz pokazać mi swoją funkcję 'mapStateToProps'? przechodzisz przez "stan"? lub 'state.booklist' – xiaofan2406

Odpowiedz

5

Osobiście używam propozycji ducks-modular-redux.

Nie jest to "oficjalny" sposób zalecany, ale działa doskonale. Każdy "kaczka" zawiera actionTypes.js, actionCreators.js, reducers.js, sagas.js i selectors.js plików. Nie ma zależności innych kaczek w tych plików, aby uniknąć cykliczną zależność lub duck circle, każdy „kaczka” zawiera tylko logikę, że trzeba zarządzać.

Następnie u nasady mam components a containers foldery i niektóre pliki root:

components/ folder zawiera wszystkie czystych składników moim app

containers/ Folder zawiera pojemniki utworzone z czyste składniki powyżej. Gdy kontener wymaga określonego selector, zawierającego wiele "kaczek", piszę go w tym samym pliku, w którym napisałem komponent <Container/>, ponieważ jest on względny w stosunku do tego konkretnego kontenera. Jeśli selector jest współdzielony przez wiele kontenerów, tworzę go w osobnym pliku (lub w HoC, który dostarcza te rekwizyty).

rootReducers.js: po prostu naraża reduktory korzeni łącząc wszystkie reduktory

rootSelectors.js naraża wybierak głównego dla każdego wycinka stanu, na przykład w danym przypadku można mieć coś takiego:

/* let's consider this state shape 

state = { 
    books: { 
     items: { // id ordered book items 
      ... 
     } 
    }, 
    taxonomies: { 
     items: { // id ordered taxonomy items 
      ... 
     } 
    } 
} 

*/ 
export const getBooksRoot = (state) => state.books 

export const getTaxonomiesRoot = (state) => state.taxonomies 

Pozwoliło nam to "ukryć" kształt stanu wewnątrz każdego pliku kaczek selectors.js. Ponieważ każdy selector odbiera cały stan wewnątrz swoich kaczek, wystarczy zaimportować odpowiednie pliki rootSelector do swoich plików selector.js.

rootSagas.js komponować wszystkie sagi wewnątrz swoich kaczek i zarządzać złożonymi przepływ udziałem wielu „kaczki”.

Tak więc w Twoim przypadku, struktura może być:

components/ 
containers/ 
ducks/ 
    Books/ 
     actionTypes.js 
     actionCreators.js 
     reducers.js 
     selectors.js 
     sagas.js 
    Taxonomies/ 
     actionTypes.js 
     actionCreators.js 
     reducers.js 
     selectors.js 
     sagas.js 
rootSelectors.js 
rootReducers.js 
rootSagas.js 

Kiedy moi „kaczki” są na tyle małe, często pominąć tworzenie folderów i bezpośrednio napisać ducks/Books.js lub ducks/Taxonomies.js plik z wszystkich tych 5 plików (actionTypes.js, actionCreators.js, reducers.js, selectors.js, sagas.js) połączone ze sobą.