Error in Redux-tookit: The store is missing a valid reducer. Ensure that the argument provided to combineReducers is an object containing reducers as values

Uh oh! Looks like there's an error with the Store reducer. The argument passed to combineReducers needs to be an object with valid reducers.

I'm having trouble setting up a Store for my app and I can't figure out where I went wrong. Could someone help me identify the issue and suggest how to resolve it?

store

import { configureStore } from '@reduxjs/toolkit';
import rootReducers from './reducers';

const store = configureStore({
  reducer: rootReducers,
});

export default store;

reducer

import handleCart from './handleCart';
import { combineReducers } from 'redux';

const rootReducers = combineReducers({
  handleCart,
});

export default rootReducers;
const cart = [];

const handleCart = (state = cart, action) => {
  const product = action.payload;
  switch (action.type) {
    case ADDITEM:
      // Check if product already exists
      const exist = state.find(x => x.id === product.id);
      if (exist) {
        return state.map(x =>
          x.id === product.id ? {...x, qty: x.qty + 1} : x,
        );
      } else {
        const product = action.payload;
        return [
          ...state,
          {
            ...product,
            qty: 1,
          },
        ];
      }
      break;
    case REMOVEITEM:
      const exist1 = state.find(x => x.id === product.id);
      if (exist1.qty === 1) {
        return state.filter(x => x.id !== exist1.id);
      } else {
        return state.map(x =>
          x.id === product.id ? {...x, qty: x.qty - 1} : x,
        );
      }
      break;
    default:
      break;
  }
};

Answer №1

Upon reviewing the handleCart reducer function code, there are a few noticeable issues that may result in exceptions being thrown. One issue is the missing return of state in the default case of the handleCart reducer function. Additionally, the REMOVEITEM case assumes the existence of the variable exist, which could potentially lead to accessing a qty property of an undefined object. It's important to remember that Array.prototype.find returns undefined when no matching element is found in the array.

Ensure that the handleCart is exported as the default so it can be imported to create the root reducer.

const cart = [];

const handleCart = (state = cart, action) => {
  const product = action.payload;

  switch (action.type) {
    case ADDITEM: {
      // Check if product exists
      const exist = state.find(x => x.id === product.id);

      if (exist) {
        return state.map(x =>
          x.id === product.id ? { ...x, qty: x.qty + 1 } : x,
        );
      }
      return [...state, { ...product, qty: 1 }];
    }

    case REMOVEITEM: {
      const exist = state.find(x => x.id === product.id);

      if (exist) {
        // Item exists, update quantity
        if (exist.qty === 1) {
          return state.filter(x => x.id !== exist1.id);
        } else {
          return state.map(x =>
            x.id === product.id ? { ...x, qty: x.qty - 1 } : x,
          );
        }
      }
      // Item didn't exist, just return current state
      return state;
    }

    default:
      // No action required, return current state
      return state;
  }
};

export default handleCart;

Although you are using redux-toolkit, consider creating a state slice. Here's a similar implementation using createSlice. This approach allows for writing reducer functions with mutable updates instead of having to shallow copy all updated parts of the state.

import { createSlice } from '@reduxjs/toolkit';

const initialState = [];

const cartSlice = createSlice({
  name: "cart",
  initialState,
  reducers: {
    addItem: (state, action) => {
      const product = state.find(product => product.id === action.payload.id);

      if (product) {
        product.qty++;
      } else {
        state.push({ ...action.payload, qty: 1 });
      }
    },
    removeItem: (state, action) => {
      const product = state.find(product => product.id === action.payload.id);

      if (product) {
        product.qty--;
        if (product.qty === 0) {
          state.filter(product => product.id !== action.payload.id);
        }
      }
    },
  },
});

export const { addItem, removeItem } = cartSlice.actions;

export default cartSlice.reducer;

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Testing Your Angular 7 Code: Unit Testing Made Easy

I am currently working on developing unit tests for this angular script: export class DataService { private csrfToken: string = ''; private isContentShown: BehaviorSubject<boolean> = new BehaviorSubject(true); constructor(private h ...

Hide Navbar when clicking on menu item

I'm struggling with finding a solution to this issue, as I am unsure of how to proceed. The problem I am facing is that when I click on an item, the router-view changes correctly, but the menu remains open. I would like it to close after a click. ...

Implementing promises in my MEAN stack application

I have developed a controller that performs a Bing search based on the user's input in the URL. After testing the controller with console.log, it seems to be functioning correctly and I have set the variable to return the results. However, when trying ...

Focus on an empty <input> tag with just the type attribute

In what way can React Testing Library be utilized to isolate a blank <input> element that solely possesses a type attribute? For instance, consider an input field that will eventually have attributes added dynamically, much like the surrounding labe ...

Troubleshooting issue with jest expect.any() failing to work with a custom class following migration from JavaScript to TypeScript

I recently made the switch to TypeScript in my project, and now some of my Jest tests are failing. It appears that the next function below is no longer being called with an AppError object, but with an Error object instead. Previously, the assertion expec ...

Guide to transferring array information from one Vuejs route to another

I'm facing an issue with passing an array from one Vuejs route to another. Specifically, I need to pass the array from home.vue to post.vue. In my route.js file for post.vue, I have: { path: '/post/:cart', name: 'post', com ...

Store the results in the database following the execution of a protractor test

I am completely new to angular protractor testing. I have created some test cases using the protractor framework with jasmine runner BDD style. Within a single test class, I have 10 to 12 specs, each with an expectation. Currently, I am running these tests ...

Encountered issue while jasmine mocking angular $http - Error: describe function does not support a done parameter

I am currently working with an angular factory that looks like this: .factory('widgetFactory', ['$http', function($http){ function getWidgets(){ return $http.get('http://example.com/api/widgets/') .then(function(re ...

What is the best way to retrieve a specific number of documents from MongoDB?

I am currently facing an issue with my code that is returning all news related to a company. However, I only want the first 15 elements. Is there a way to achieve this? The following code snippet retrieves all news for a company using the google-news-jso ...

Enhancing material appearance by incorporating color gradient through the extension of three.js Material class using the onBeforeCompile method

In my three.js scene, I have successfully loaded an .obj file using THREE.OBJLoader. Now, I am looking to add a linear color gradient along the z-axis to this object while keeping the MeshStandardMaterial shaders intact. Below is an example of a 2-color l ...

Tips for creating a dynamic variable for an object key in jQuery to streamline your code

Utilizing the TweenMax library, I am adding styles to a div while scrolling. However, I am facing a challenge where I need different styles based on varying page resolutions. To address this issue, I implemented an if condition. Is there a way I can use a ...

Encountering an issue with Node JS request and cheerio while parsing an HTML page

Greetings all, I am currently attempting to parse a website using Node.js (utilizing request and cheerio). The issue I am encountering is that I am trying to extract the href from the site, but I can only find it within the site's window. Unfortunatel ...

How to Handle Tab Navigation on a Mobile Website without Javascript?

My website primarily targets mobile devices, with tabs in the top navigation. Currently, these tabs are hard coded instead of utilizing Javascript. We want to ensure our site is accessible on all mobile devices, including those without Javascript support. ...

Could the slow loading time of the React site be attributed to an overload of static assets?

As a ML professional diving into frontend development, I have recently incorporated various fixed assets such as images into the assets folder for React. However, I've noticed that my website is running slower than expected. Do you believe that these ...

Tips for refining a list to only include items that contain every element from a specified array

Is there a way to search for all elements in an array and display them if they are all present? For instance, consider the following: const data = [ { "languages": ["JavaScript"], "tools": ["React", "Sass"] }, { "languages": ["Python" ...

What is the best way to run a callback once several Ajax requests have finished?

I am facing a challenge with executing a callback function after multiple jQuery Ajax requests have been completed. The issue arises when these Ajax requests call another function, resulting in the functions being undefined. I suspect that the root of ...

The progress event of the XMLHttpRequest updates quickly, outpacing the speed of the upload itself

I've been working on setting up an upload form and using xhr to return the upload status to the user. Everything seems to be in place, but I'm facing a strange issue where the callbacks are happening too quickly and showing a higher percentage th ...

Steps for clearing input field with type=date in Protractor:

I am currently working with protractor version 4.0.4 and I'm encountering an issue where I cannot clear a date input field. It seems like Chrome is introducing some extra controls that are causing interference. You can find further details about Chro ...

When using node.js, the Ajax success function is not being executed

Why doesn't success respond? Here is the code I've used: Client-side code: function add(){ var values = formserial(addd); var tok = "abc", var url= 'http://localhost:8181/add'; $.ajax({ type: "POST", ...

Webpack automatically prepends "auto/" to script tags in the compiled HTML file

I am currently setting up an application for coding, but I am facing a problem with webpack. Every time I build the application, webpack automatically adds "auto/file.js" to the script tags instead of just "file.js". I have checked all my webpack configura ...