Search code examples
javascriptreactjsreduxreact-reduxredux-thunk

Getting an error that I need to use middleware, but I have already applied middleware


Okay so I am following a tutorial, and I'm a beginner. This is my first experience with Redux.

This is the error I've been getting when it should be displaying the home screen of my webpage.

Actions must be plain objects. Instead, the actual type was: 'string'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions. See https://redux.js.org/tutorials/fundamentals/part-4-store#middleware and https://redux.js.org/tutorials/fundamentals/part-6-async-logic#using-the-redux-thunk-middleware for examples.

I have been searching everywhere but it looks to me like I applied thunk correctly. I'm hoping someone more experienced will be able to spot my mistake. Thank you.

HomeScreen.js

import React, { useEffect } from 'react';
import {Link} from 'react-router-dom';
import { listProducts } from '../actions/productActions.js';

import { useDispatch, useSelector } from 'react-redux';

function HomeScreen() {

    
    const productList = useSelector(state => state.productList);
    const { products, loading, error} = productList;
    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(listProducts());
        return () => {
            //
        };
    }, [])

    return loading? <div>Loading...</div> :
    error? <div>{error}</div>:
    <ul className="products">
    {
      products.map(product =>
        <li key={product._id}>
            <div className="product">
                <Link to={'/product/' + product._id}>
                    <img className="product-image" src={product.image} alt="product" />
                </Link>
                <div className="product-name">
                    <Link to={'/product/' + product._id}>{product.name}</Link>
                </div>
                <div className="product-brand">{product.brand}</div>
                <div className="product-price">${product.price}</div>
                <div className="product-rating">{product.rating} Stars ({product.numReviews} Reviews)</div>
            </div>
        </li>)
    }
  </ul>
}
export default HomeScreen;

store.js

import { createStore, combineReducers, applyMiddleware } from 'redux';
import { productListReducer } from './reducers/productReducers.js';
import thunk from 'redux-thunk';
import * as compose from 'lodash.flowright';

const initialState = {};
const reducer = combineReducers({
    productList: productListReducer,
})

const composeEnhancer = window.__REDUXDEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, initialState, composeEnhancer(applyMiddleware(thunk)));
export default store;

productActions.js

import { PRODUCT_LIST_FAIL, PRODUCT_LIST_REQUEST, PRODUCT_LIST_SUCCESS } from "../constants/productconstants.js";
import axios from "axios";

const listProducts = () => async (dispatch) => {

    try {
        dispatch(PRODUCT_LIST_REQUEST);
        const {data} = await axios.get("/api/products");
        dispatch({type: PRODUCT_LIST_SUCCESS, payload: data});
    }
    catch (error) {
        dispatch({type: PRODUCT_LIST_FAIL, payload:error.message});
    }
}

export {listProducts};

productReducers.js

import { PRODUCT_LIST_FAIL, PRODUCT_LIST_REQUEST, PRODUCT_LIST_SUCCESS } from "../constants/productconstants";

function productListReducer(state= {products: [] }, action) {

    switch (action.type) {
        case PRODUCT_LIST_REQUEST:
            return {loading:true};
        case PRODUCT_LIST_SUCCESS:
            return {loading:false, products: action.payload};
        case PRODUCT_LIST_FAIL:
            return {loading:false, error: action.payload};
        default: 
            return state;
    }
}

export { productListReducer }

Solution

  • PRODUCT_LIST_REQUEST appears to be a string. You cannot dispatch a string by itself - only action objects. Actions are always objects that have a type field inside, like {type: 'counter/incremented'}.

    That said, you should be using our official Redux Toolkit package to write your Redux code. Redux Toolkit will simplify all of the Redux store setup and reducer logic you've shown.