skip to Main Content

I am trying to store some data from an API into my Redux store but when I try to dispatch I get this error:

TypeError: prepareAction is not a function

Below is my code regarding the redux store:

store.js

import {
  compose,
  legacy_createStore as createStore,
  applyMiddleware
} from "redux";
import logger from "redux-logger";
import { thunk } from "redux-thunk";

import { rootReducer } from "./root-reducer";
import { INITIAL_STATE } from "./absence/absences.reducer";

// middleware
const middleware = [logger, thunk];
const composedEnhancers = compose(applyMiddleware(...middleware));

//root-reducer

export const store = createStore(rootReducer, INITIAL_STATE, composedEnhancers);

root-reducer.js

import { combineReducers } from "redux";

import { absenceReducer } from "./absence/absences.reducer";

export const rootReducer = combineReducers({
  absences: absenceReducer,
});

absence.action.js

import { createAction } from "@reduxjs/toolkit";

import { ABSENCE_ACTION_TYPES } from "./absences.types";

export const setAbsences = (absences) =>
  createAction(ABSENCE_ACTION_TYPES.SET_ABSENCES, absences);

absence.reducer.js

import { ABSENCE_ACTION_TYPES } from "./absences.types";

export const INITIAL_STATE = {
   absences: [],
};

export const absenceReducer = (state = INITIAL_STATE, action) => {
   const { type, payload } = action;

  switch (type) {
    case ABSENCE_ACTION_TYPES.SET_ABSENCES:
      return { ...state, absences: payload };
      break;

    default:
      return state;
  }
};

absence.selector.js

export const selectAbsences = (state) => state.absences;

absence.types.js

export const ABSENCE_ACTION_TYPES = {
  SET_ABSENCES: "SET_ABSENCES",
};

App.js

import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import axios from "axios";

import "./App.css";
import { setAbsences } from "./store/absence/absences.action";
import { selectAbsences } from "./store/absence/absences.selectors";

function App() {
  const absences = useSelector(selectAbsences);
  const dispatch = useDispatch();

  useEffect(() => {
    const getAbsences = async () => {
      const result = await axios.get(
        `https://front-end-kata.brighthr.workers.dev/api/absences`
      );
  
      dispatch(setAbsences(result));
  
    };
    getAbsences();
  }, []);

  return (
    <div className="App">
      <h1>List of absences</h1>
    </div>
). ;
}

export default App;

I have checked the API call is working fine I am getting the data, but when it hits the dispatch it gives me that error.

2

Answers


  1. I believe you are not correctly using createAction.
    Instead of doing

    import { ABSENCE_ACTION_TYPES } from "./absences.types";
    
    export const setAbsences = (absences) =>
      createAction(ABSENCE_ACTION_TYPES.SET_ABSENCES, absences);
    

    Try

    import { ABSENCE_ACTION_TYPES } from "./absences.types";
    
    export const setAbsences = (absences) => ({
      type: ABSENCE_ACTION_TYPES.SET_ABSENCES,
      payload: absences,
    });
    

    Make sure you make the necessary changes in App.js too

    useEffect(() => {
      const getAbsences = async () => {
        try {
          const result = await axios.get(
            `https://front-end-kata.brighthr.workers.dev/api/absences`
          );
          dispatch(setAbsences(result.data));
        } catch (error) {
          console.error("Error fetching absences:", error);
        }
      };
      getAbsences();
    }, []);
    
    Login or Signup to reply.
  2. Issue

    createAction is the utility function that creates the action creator to be dispatched. You appear to be mixing older legacy methodologies with current Redux.

    export const setAbsences = (absences) =>
       createAction(ABSENCE_ACTION_TYPES.SET_ABSENCES, absences);
    

    The above is a function that creates the action creator… but it doesn’t itself create the action object yet.

    Solution

    Update setAbsences to the following:

    export const setAbsences = createAction(ABSENCE_ACTION_TYPES.SET_ABSENCES);
    

    Now when setAbsences is called it will return an action object of the following shape:

    {
      type: ABSENCE_ACTION_TYPES.SET_ABSENCES
      payload: /* whatever value passed to action creator */
    }
    

    See createAction for complete details.

    Suggestion

    Since you are using Redux-Toolkit you may as well write current Redux state slices as well.

    Example:

    import { createSlice } from "@reduxjs/toolkit";
    
    const initialState = {
      absences: [],
    };
    
    const absenceSlice = createSlice({
      name: "absence",
      initialState,
      reducers: {
        setAbsences: (state, action) => {
          state.absences = action.payload,
        },
      }
    });
    
    export const { setAbsences } = absenceSlice.actions;
    
    export default setAbsences.reducer;
    

    root-reducer:

    import { combineReducers } from "@reduxjs/toolkit";
    import absenceReducer from "./absence/absencesSlice";
    
    export const rootReducer = combineReducers({
      absences: absenceReducer,
    });
    

    store:

    import { configureStore } from "@reduxjs/toolkit";
    import logger from "redux-logger";
    import { rootReducer } from "./root-reducer";
    
    export const store = configureStore({
      reducer: rootReducer,
      middleware: getDefaultMiddleware => 
        getDefaultMiddleware.concat(logger);
    );
    

    Redux-Toolkit cuts out much of the old legacy boilerplate, it’s no longer necessary.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search