0

I am trying to use the createAction function but am met with the following error:

Uncaught Error: Actions may not have an undefined "type" property. Have you misspelled a constant?

I'm not sure why I am getting this but I am assuming it has to do with middleware but I've tried adding that too and it still wont work.

this is what my store looks like:

import { combineReducers, applyMiddleware, compose } from "redux";
import { configureStore } from "@reduxjs/toolkit";
import { routerMiddleware } from "react-router-redux";
import thunk from "redux-thunk";
import { apiMiddleware } from "redux-api-middleware";
import Immutable from "immutable";

import moduleReducers from "./reducers";
import routerReducer from "./reactRouterReducer";

export default function createStore(history, initialState) {
  const middlewares = [thunk, apiMiddleware, routerMiddleware(history)];
  const enhancers = compose(applyMiddleware(...middlewares));

  const reducer = combineReducers({
    router: routerReducer,
    ...moduleReducers,
  });

  const preLoadedState = Immutable.fromJS(initialState || {});
  return configureStore({
    reducer,
    preLoadedState,
    enhancers,
  });
}

this is what my reducer looks like:

import { createAction } from "redux-api-middleware";
import { createSelector } from "reselect";
import deep from "deep-get-set";
import config from "../config/config";

const SET_PROJECT = "SET_PROJECT";
const SET_PROJECTS = "SET_PROJECTS";
const SET_LOADING = "SET_LOADING";
const SET_ERROR = "SET_ERROR";

const initialState = {
  isLoading: false,
  hasError: false,
  user_projects: null,
  project: null,
};

export const fetchProjectsList = () =>
  createAction({
    endpoint: `${config?.apiHost}/projects`,
    method: "GET",
    headers: [],
    credentials: "include",
    types: [SET_LOADING, SET_PROJECTS, SET_ERROR],
  });
export default function reducer(state = initialState, action) {
  switch (action.type) {
    case SET_PROJECT: {
      const newState = {
        ...state,
        isLoading: false,
        hasError: false,
        project: action?.project,
      };
      return newState;
    }
    case SET_PROJECTS: {
      const newState = {
        ...state,
        isLoading: false,
        hasError: false,
        user_projects: action?.payload,
      };
      return newState;
    }
    case SET_LOADING: {
      const newState = {
        ...state,
        isLoading: true,
        hasError: false,
        project: action?.project,
      };
      return newState;
    }
    case SET_ERROR: {
      const newState = {
        ...state,
        isLoading: false,
        hasError: true,
        project: action?.project,
      };
      return newState;
    }
    default:
      return state;
  }
}

I've tried setting up my store in all sorts of ways with different redux versions and still get the same error. It's funny cause I used this exact same function for a class and was able to use it successfully but for some reason I am lost on why this isn't working now. I know for a fact that the createAction function takes an object with a types key. I'm out of options. PLEASE HELP!

1 Answers1

0

While this isn't a direct answer to your question, I have a few suggestions on how you can improve that code.

First, with Redux Toolkit's configureStore API you don't have to do all the middleware setup and composing yourself. Instead, you can do:

  return configureStore({
    reducer,
    preLoadedState,
    middleware: (getDefaultMiddleware) => 
      getDefaultMiddleware()
        .concat(apiMiddleware, routerMiddleware(history))

  });

Second, as a general observation: we specifically recommend against using Immutable.js, and instead recommend that you should use Immer for immutable updates:

More specifically, Redux Toolkit's createSlice API already has Immer built in. It also automatically generates action creators and action types for you, so you don't have to write any of those yourself:

And finally, Redux Toolkit includes our "RTK Query" data fetching and caching API, which can eliminate the need for writing any actions, thunks, middleware, reducers, or effects for fetching data:

As an example, all of this file could probably be replaced with:

import { createApi, fetchBaseQuery} from "@reduxjs/toolkit/query/react";

const api = createApi({
  baseQuery: fetchBaseQuery({
    baseUrl: `${config?.apiHost ?? ''}`,
    endpoints: (build) => ({
      getProjects: build.query({
        query: () => '/projects'
      })
    })
  })
)}

export const { useGetProjectsQuery } = api;

Add the RTK Query API middleware and reducer to the store setup, use the query hook in a component, and all the data fetching and caching is done for you automatically!

markerikson
  • 63,178
  • 10
  • 141
  • 157