Redux: Organizing Containers, Components, Actions, and Gearboxes

Question:

What is the most convenient and recommended best practice for organizing containers, components, actions, and gears in a large React / Redux application?

My opinion:

Existing trends seem to organize reductant gates (actions, gears, sagas ...) around a related container component. eg.

/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 

It works great! Although it seems there are a couple of problems with this design.

Problems:

When we need to access actions , selectors or sagas from another container, it seems like an anti-pattern. Let's say we have a global container /App with a reducer / state that stores information that we use throughout the application, such as categories and enumerations. Following the above example with a state tree:

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

If we want to use the selector from the /App container in our /BookList container, we need to either recreate it in /BookList/selectors.js (certainly wrong?) OR import it from /App/selectors (will always be EXACT same selector ..? no.). Both of these ratings seem to me suboptimal.

A striking example of this use case is authentication (ah ... auth, we love to hate you), as this is a VERY common side effect model. We often have to access /Auth sagas, actions and selectors throughout the application. We can have containers /PasswordRecover , /PasswordReset , /Login , /Signup .... Actually, in our application, our /Auth contianer does not have any valid component at all!

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

Just containing all the Redux backups for the various and often unrelated auth containers mentioned above.

+6
source share
1 answer

I personally use the ducks-modular-redux clause .

This is not an โ€œofficialโ€ recommended method, but it works great for me. Each duck contains actionTypes.js , actionCreators.js , reducers.js , sagas.js and selectors.js files. In these files there is no dependency on other ducks, in order to avoid cyclic dependence or the circle of a duck , each "duck" contains only the logic by which it should be controlled.

Then in the root folder there are folders components and containers and some root files:

components/ folder contains all clean components of my application

containers/ folder contains containers created from the clean components above. When a container requires a specific selector containing a lot of ducks, I write it in the same file where I wrote the <Container/> component, since it refers to this particular container. If the selector is shared between several containers, I create it in a separate file (or in HoC, which provides these details).

rootReducers.js : simply provides root reducers by combining all reducers

rootSelectors.js provides a root selector for each state slice, for example, in your case, you might have something like:

 /* let 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 

It allows us to โ€œhideโ€ the state form inside each ducks selectors.js file. Since each selector gets the full state inside your ducks, you just need to import the corresponding rootSelector into your selector.js files.

rootSagas.js compose all the sagas inside your ducks and manage a complex flow involving many ducks.

So, in your case, the structure could be:

 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 

When my โ€œducksโ€ are small enough, I often skip creating a folder and directly write the ducks/Books.js or ducks/Taxonomies.js file with all these 5 files ( actionTypes.js , actionCreators.js , reducers.js , selectors.js , sagas.js ).

+5
source

All Articles