Search code examples
reactjsreduxredux-toolkit

Redux Toolkit Extra Reducer fetch data api not working


I'm creating an analysis app and would like to store industry data for businesses in a global state. I'm trying to load this data once using Redux but can't seem to get the fetch data extra reducer to work using the latest toolkit release in Aug 2023. Global states for other parameters seem to be working, just not the ability to fetch data once and store it in the beginning of an analysis. The API works as I tested it with postman and other apps. Node server is being pinged when the page loads the first time but functions don't seem to be working. I don't even think the extra reducer function, getIndustryData is exporting properly.

import { createSlice, createAsyncThunk} from "@reduxjs/toolkit";
import db from '../../components/apis/db'

export const getIndustryData = createAsyncThunk(
  'analysis/getIndustryData',
  async () => {
    //using axios object db in another file to fetch data..
    const response = await db.get("/getTable/industries")
    //note: response already accounts for data in axios on the server side
    const data=response
    return data;
  }
);

const initialState = {
  revenue: 5000000000,
  spend: 10000000,
  industryData: [],
  fetchDataStatus: "",
}

export const analysisSlice = createSlice({
  name: 'analysis',
  initialState,
  reducers: {
    update: (state, action) => {
      state = action.payload;
    },
    reset: (state) => {
      state = initialState;
    },
    extraReducers: (builder) => {
      builder
        .addCase(getIndustryData.pending, (state) => {
          state.fetchDataStatus= "pending";
        })
        .addCase(getIndustryData.fulfilled, (state, action) => {
          state.fetchDataStatus= "fulfilled";
          state.industryData = action.payload.forEach(item => {
            state.industryData.push(item)
          })
        })
        .addCase(getIndustryData.rejected, (state) => {
          state.fetchDataStatus= "rejected";
        })
    }
  }  
});

export const { update, reset} = analysisSlice.actions;
export default analysisSlice.reducer

Component

const DataTest = () => {
  const analysisParams = useSelector((state) => state.analysis)  
  const dispatch = useDispatch()
    
  useEffect(() => {
    dispatch(getIndustryData)
  }, [])
    
  return (
    <div style={{ display: "block", width: 300 }}>
      <h3>Global paramaters:</h3>
      <p>{JSON.stringify(analysisParams)}</p>
    
      <h3>Industry Data:</h3>
      <p style={{ padding: 20 }}>
        {JSON.stringify(analysisParams.industryData)}
      </p>
    </div>
  )
}

export default DataTest

Solution

  • Everything you have done is perferct but you shouldn't put extraReducers inside the reducers, it should be declared outside of reducers

    export const analysisSlice = createSlice({
        name: 'analysis',
        initialState,
        reducers: {
            update: (state, action) => {
                state = action.payload;
            },
            reset: (state) => {
                state = initialState;
            }
        },  
        extraReducers: (builder) => { // ouside the reducers!
            builder
            .addCase(getIndustryData.pending, (state) => {
                state.fetchDataStatus= "pending";
            })
            .addCase(getIndustryData.fulfilled, (state, action) => {
                state.fetchDataStatus= "fulfilled";
                state.industryData = action.payload.forEach(item=>{
                    state.industryData.push(item)
                })
            })
            .addCase(getIndustryData.rejected, (state) => {
                state.fetchDataStatus= "rejected";
            })
        }
    });