Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redux - One vs Multiple reducers

I come from the Elm-comunity and in Elm, every application has its view, its model and its state and basically takes very similar approach, IMO, to solving problems as redux does.

Anyway, I found myself struggling with the idea of multiple reducers. In Elm I am used to make a separate file for all the actions (Messages), a separate file for "react" (View), a separate one for state (Model), and a separate one for all the reducers (Update).

Every possible action gets covered inside Update file and Update file cannot be spread trough multiple files, keeping all the logic in one place.

On the other hand, Redux encourages making multiple separate files for reducers and later on combining them with combineReducers, which I found very confusing and more or less a disadvantage rather than an advantage.

If I get things right, each reducers only gets the part it's "responsible" for and is able to do something with it and different reducers cannot access other state-properties/properties of other reducers.

Cons of doing this IMO:

  1. Function from reducer A may need info about information from reducer B, but cannot be accessed because of this.
  2. More files lead to more mess and unintentional errors.
  3. Unnecessary code splitting. ...

What are the pros of splitting code or am I not seeing something here?

like image 727
maticzav Avatar asked May 04 '17 08:05

maticzav


People also ask

Why use multiple reducers in Redux?

Multiple slice reducers can respond to the same action, independently update their own slice as needed, and the updated slices are combined into the new state object. Because this pattern is so common, Redux provides the combineReducers utility to implement that behavior.

How many reducers should I use Redux?

A Redux app really only has one reducer function: the "root reducer" function that you will pass to createStore later on. That one root reducer function is responsible for handling all of the actions that are dispatched, and calculating what the entire new state result should be every time.

Can Redux have multiple reducers?

Having multiple reducers become an issue later when we create the store for our redux. To manage the multiple reducers we have function called combineReducers in the redux. This basically helps to combine multiple reducers into a single unit and use them.

What is the difference between reducer and Redux?

Reducers are a pure function in Redux. Pure functions are predictable. Reducers are the only way to change states in Redux. It is the only place where you can write logic and calculations.


1 Answers

I'll attempt to explain before Dan Abramov spots this thread and writes another amazing answer :-)

Cons:

Function from reducer A may need info about information from reducer B, but cannot be accessed because of this.

This problem doesn't really happen, because it's completely up to you how the reducers should be combined. If a reducer is interested in only a part of the state tree, then combineReducers would make sure it only receives that part. But if it needs more state, then you'd apply this particular reducer in a way that it receives the whole state.

The whole application is going to have only one reducer in the end - one that handles the whole state and all the actions - but you'll probably want to split up your application code into topic-related modules at some point, so it's easier to write smaller topic-related reducers and them combine them into one. combineReducers is just a helper that lets you do that conveniently when you want to.

  1. More files lead to more mess and unintentional errors.
  2. Unnecessary code splitting. ...

Up to you when to split your code. I like to keep unrelated functionality in different files. For example if my web app has a chat module, I'll probably make a chat package and put all chat-related code in there - a view, a bunch of actions and the reducer that understands these actions.


Moving on to pros:

combineReducers is helpful because it works really well with re-usable apps. For instance I can write a module that deals with comments... Part of it will be a reducer like:

const initialState = {
  commentList: [],  // list of { author, text, upvotes }
  commentingAllowed: true,
}

function commentReducer(state, action) {
  if (typeof state === 'undefined') {
    return initialState;
  }
  switch (action.type) {
    // ...
  }
}

but the actual state of my application can be more complex, like:

{
  currentArticle: {
    title: "Some article",
    published: "2017-04-05",
    author: "someone",
    comments: {
      commentList: [],
      commentingAllowed: true,
    }
  }
}

The comment state is nested under currentArticle, but my comments app (and specifically commentReducer is not aware about the whole concept of articles! So I don't want it to receive the whole state - it wouldn't know what to do with it. I want this reducer to only receive the part of the state that corresponds to its comments.

Note that I could have many articles at once, also maybe other commentable things. With clever combining of reducers, you could have multiple "instances" of the comments app, each only taking care of its own small bit of state. This requires a bit smarter glue code than combineReducers alone, but it shows the kind of situation when it's natural for a reducer to only want a specific part of the application state - separation of concerns.

like image 173
Kos Avatar answered Oct 06 '22 22:10

Kos