React Redux: Should reducers contain any logic

redux-logic
redux-thunk
redux reducer
react business logic
react reducer pattern
react/redux project structure 2019
redux dispatch
redux ducks

I have a cart reducer function with add, update and delete cases. I also have a product array within the redux store. When there are two items added to the product array, instead of having two items, I increment the quantity value. My main question is, should the reducers include any logic i.e. determine if the products array already contains the exact product and just returns an update on quantity of product or should this behavior be handled within the presentational component checking for existing products and either adding a new product or updating the quantity?

function CartReducer (state = initialState, action) {
  switch (action.type) {
    case AddToCart:
      return {
        ...state,
        products: [...state.products, action.product],
        totalPrice: state.totalPrice += (action.price * action.quantity)
      }

    case RemoveItemCart:

      return {
        ...state,
        products: [
          ...state.products.slice(0, action.index),
          ...state.products.slice(action.index + 1)
        ]
      }

    case UpdateItemQuantity:
      return {
        ...state,
        products: state.products.map((product, index) => {
          if (index === action.index) {
            return Object.assign({}, product, {
              quantity: action.quantity
            })
          }
          return product
        })
      }

    default:
      return state
  }
}

Per the Redux FAQ entry on splitting logic between reducers and action creators:

There's no single clear answer to exactly what pieces of logic should go in a reducer or an action creator. Some developers prefer to have "fat" action creators, with "thin" reducers that simply take the data in an action and blindly merge it into the corresponding state. Others try to emphasize keeping actions as small as possible, and minimize the usage of getState() in an action creator. (For purposes of this question, other async approaches such as sagas and observables fall in the "action creator" category.)

There are some potential benefits from putting more logic into your reducers. It's likely that the action types would be more semantic and more meaningful (such as "USER_UPDATED" instead of "SET_STATE"). In addition, having more logic in reducers means that more functionality will be affected by time travel debugging.

This comment sums up the dichotomy nicely:

Now, the problem is what to put in the action creator and what in the reducer, the choice between fat and thin action objects. If you put all the logic in the action creator, you end up with fat action objects that basically declare the updates to the state. Reducers become pure, dumb, add-this, remove that, update these functions. They will be easy to compose. But not much of your business logic will be there. If you put more logic in the reducer, you end up with nice, thin action objects, most of your data logic in one place, but your reducers are harder to compose since you might need info from other branches. You end up with large reducers or reducers that take additional arguments from higher up in the state.

I also wrote my own thoughts on "thick and thin" reducers:

There's valid tradeoffs with putting more logic in action creators vs putting more logic in reducers. One good point that I saw recently is that if you have more logic in reducers, that means more things that can be re-run if you are time-travel debugging (which would generally be a good thing).

I personally tend to put logic in both places at once. I write action creators that take time to determine if an action should be dispatched, and if so, what the contents should be. However, I also often write corresponding reducers that look at the contents of the action and perform some complex state updates in response.

update

As of 2020, we specifically recommend putting as much logic as possible in reducers:

Wherever possible, try to put as much of the logic for calculating a new state into the appropriate reducer, rather than in the code that prepares and dispatches the action (like a click handler). This helps ensure that more of the actual app logic is easily testable, enables more effective use of time-travel debugging, and helps avoid common mistakes that can lead to mutations and bugs.

There are valid cases where some or all of the new state should be calculated first (such as generating a unique ID), but that should be kept to a minimum.

Code Structure, How should I split my logic between reducers and action creators? possible ( and encouraged) for a reducer defined in one folder to respond to an action to have “fat” action creators, with “thin” reducers that simply take the data in an action� Here’s a simple example of how I implemented the reducer function in React. See the Pen reducer example by Kingsley Silas Chijioke (@kinsomicrote) on CodePen. You can see that I didn’t make use of Redux, but this is very much the same way Redux uses reducers to store and update state changes.

Reusing Reducer Logic, As an application grows, common patterns in reducer logic will start to emerge. Or, you may want to have multiple "instances" of a certain type of data being handled in the store track the overall state of an application, but can also make it harder to "target" respond to all 'INCREMENT' actions, but never ' DECREMENT'. You can only write "mutating" logic in Redux Toolkit's createSlice and createReducer because they use Immer inside! If you write mutating logic in reducers without Immer, it will mutate the state and cause bugs!

React Redux: Should reducers contain any logic - reactjs - html, My main quetion is, should the reducers contain any logic i.e. determine if the products array already contains the exact product and just returns an update on� Although people say redux is a bit complicated and has a lot of boilerplate code. That is true, but up to an extend. The truth be told is you can become an expert in Redux if you get the knack of it.

Consider what you might want to do in your middleware...if you put all your logic inside your reducer then the record in the middleware will not have the business logic applied to it.

  1. dispatch(new UpdatePerson(person))
  2. run middleware and intercept the UpdatePerson action
  3. reducer - updates the age value for person

if you want to say, save your record in a store, then the reducer logic will run too late and you won't have access to the changed record in the state you require it in your middleware.

Where do I put my business logic in a React-Redux application?, This is a question that we have all struggled with in building applications. to find the best approach to structuring business logic in my React + Redux app. Reducers operate synchronously so they can't directly initiate� Reducer functions must not contain unpredictable code, or perform side-effects such as network requests, and should not directly mutate the state object. Redux is a great tool, as we’ll learn later in this guide, but it doesn’t come without its challenges or tradeoffs.

Understanding How Reducers are Used in Redux, A reducer is a function that determines changes to an application's We have tools, like Redux, that help manage an application's state There is typically a payload value that contains what the user is sending and would be Here's a simple example of how I implemented the reducer function in React. By itself, a Redux store doesn't know anything about async logic. It only knows how to synchronously dispatch actions, update the state by calling the root reducer function, and notify the UI that something has changed. Any asynchronicity has to happen outside the store.

The complete beginners guide to Redux reducers with code examples, In Redux, you should always have a initial state object. Okay let's add a bit more logic to this reducer function. DO NOT put all of your React state in Redux . Tests become dependent on implementation details of reducers, sages, etc. This blog post describes how you can write integration tests for React Native apps with Redux, using React Native Testing Library. The setup described here allows us to test all application parts together, in conditions resembling normal app operation when components are

The Secret to Using Redux at Scale | by Kevin Ghadyani, For instance, I have to work on a project where logic is shared among Neither React's component state nor the Context API have anything like this. Here's an example using the same loading state reducer and actions we� State management is a critical part in React development and many tools have been created to assist developers with this task. The most popular one is Redux, a small library created by Dan Abramov to…

Comments
  • reducers can have any logic you want as long as they stay pure. pure means no side effects such as async calls or changing or relying on objects outside their context nor mutating their state .
  • React+redux is to frontend the same that CQRS+Event sourcing to backend. Dispatching actions is essentially putting messages on the event queue. Applying reducers on them is basically handling storage. So, in my opinion, the logic that goes into reducers should only pertain to how the state is stored, incl. optimization, consistency and stuff.
  • see youtube/fU9hR3kiOK0?t=21m6s for reference - you can imagine the event stream as actions. When he talks about materialized views, the redux store would be a primary one. Reducer then would be a function that incrementally transforms the store with respect to actions. Reducer needs to be immutable - all side effects need to be handled by actions. As to other materialized views, they can be thought of as the intermediate state produced by selectors applied to the state. Essentially, composing reducer and selector is still a transformation function.