0

When action ends extraReducer is not being called

I'm trying fetch for this url, which will return a list of items to me, fetchItems method is called by dispatch, but at the end, the extra reducer at line:55 is not called. Maybe I'm not undestanding the logic of extraReducers, but its code is based on redux-toolkit documentation

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";

export const fetchItens = createAsyncThunk('table/fetchItens/ful', async (payload, thunkAPI) => {
    let returnedData = null;

    if (payload.serie === 0) {
        console.log(payload)
        await fetch('http://localhost:3006/campeonatos/brasileiraoA').then(async function (response) {
            await response.json().then(function (data) {
                if (data.error) {
                    console.log("Ocorreu um erro.")
                } else {
                    returnedData = data.dados
                }
            });
        }).catch(function (err) {
            console.error('Ocorreu um erro.', err);
        });

    }
    if (payload.serie === 1) {
        console.log(payload)
        await fetch('http://localhost:3006/campeonatos/brasileiraoB').then(async function (response) {
            await response.json().then(function (data) {
                if (data.error) {
                    console.log("Ocorreu um erro.")
                } else {
                    returnedData = data.dados
                }
            });
        }).catch(function (err) {
            console.error('Ocorreu um erro.', err);
        });
    }

    return returnedData;
})

export const slice = createSlice({
    name: 'counter',
    initialState: {
        dates: [

        ]
    },
    reducers: {
        setDate: (state, { payload }) => {
            return {
                ...state,
                dates: payload.dates
            }
        }
    },
    extraReducers: (builder) => {
        builder.addCase(fetchItens.fulfilled, (state, { payload }) => {
            payload.map((item) => state.dates.push(item))
        })
    }
});

export const { setDate } = slice.actions;

export const getDates = (state) => state.dates

export default slice.reducer;

It's store setup

import navigationReducer from "./navigationSlice";
const { combineReducers, configureStore, getDefaultMiddleware } = require("@reduxjs/toolkit")

export default configureStore(
    {
        reducer: combineReducers({
            selectedElement: navigationReducer
        }),
        
    }
); 

Its where is called

const { selectedElement } = useSelector(getSelectedElement)

  useEffect(() => {
    // console.log(selectedElement)
    dispatch(fetchItens({
      serie: selectedElement
    }));
  }, [selectedElement])
Biel
  • 1
  • 3

2 Answers2

1

First of all I am also learning redux and will be based on my personal experience learning redux in the past few weeks.

Your extra reducer is only getting called when your promise is fulfilled. It might be the case that your response isn't being fulfilled.

The fact that you are using async/await syntax along with then makes your code isn't good practice and might be causing issues. By using async/await syntax efficiently your async thunk action creators would be:

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'

// Thunk creator
// Instead of calling he args payload you can get the "serie" directly and using it when dispatching the acion
export const fetchItens = createAsyncThunk('table/fetchItens/ful', async (serie, thunkAPI) => {

// using async/await 
    if (serie === 0) {
        try {
            const response = await fetch('http://localhost:3006/campeonatos/brasileiraoA')
            const returnedData = await response.json()
            return returnedData.dados
        } catch (error) {
            console.log("Ocorreu um erro.")
        }
    }
    if (serie === 1) {
        try {
            const response = await fetch(
              'http://localhost:3006/campeonatos/brasileiraoB'
            )
            const returnedData = await response.json()
            return returnedData.dados
        } catch (error) {
            console.log('Ocorreu um erro.')
        }
        
    }
    return null
})

// Added cases for pending and rejected
export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
      dates: [],
      status: 'idle',
      errors: []
  },
  reducers: {
    setDate: (state, { payload }) => {
      return {
        ...state,
        dates: payload.dates
      }
    }
  },
  extraReducers: builder => {
    builder.addCase(fetchItens.pending, (state) => {
        state.status = 'loading'
    }).addCase(fetchItens.rejected, (state, { payload }) => {
        state.status = 'failed'
        state.errors.push(payload)
    }).addCase(fetchItens.fulfilled, (state, { payload }) => {
        state.status = 'succeded'
      payload.map(item => state.dates.push(item))
    })
  }
})

export const { setDate } = counterSlice.actions

export const getDates = (state) => state.dates

export default counterSlice.reducer

What is the name of this file? Is this inside navigationReducer.js? Since the name of the slice is counter, let's assume it is called counterReducer.js.

If that is in a separate file from navigationReducer.js you also need to add that when defining your store. I also removed getDefaultMiddleware since it doesn't seem that you are using it.

import navigationReducer from "./navigationSlice";
import counterReducer from "./counterSlice"; 
import { combineReducers } from 'redux'
import { configureStore } from '@reduxjs/toolkit'


const reducer = combineReducers({
  selectedElement: navigationReducer,
  counter: counterReducer,
  notification: notificationReducer
})

const store = configureStore({
  reducer
})

export default store

Since I don't know your folder structure I am also assuming that your components are in the same folder as your reducers

YourComponent.js

import { useEffect } from "react"
import { useSelector, useDispatch } from "react-redux"
import { fetchItens } from "./counterSlice"

const YourComponent = () => {
  const { selectedElement } = useSelector(getSelectedElement)
  const dispatch = useDispatch()

  useEffect(() => {
    console.log(selectedElement)
    // sending selectedElement directly as you are already getting it as args in your thunk creator
    dispatch(fetchItens(selectedElement))
  }, [selectedElement])

  // render something
}

export default YourComponent

}

Hopefully this will be able to help you. I might be able to try clarify things in portuguese through dms if you need.

References: https://redux-toolkit.js.org/api/createAsyncThunk

This is my first contribution in Stack Overflow, I'd appreciate some feedback as well!

dev0T
  • 73
  • 7
0

Your getDates selector would need to be

export const getDates = (state) => state.selectedElement.dates

for it to return anything other than undefined, assuming you use it like

const dates = useSelector(getDates)

Is that maybe your problem?

phry
  • 35,762
  • 5
  • 67
  • 81
  • No, its not the problem, when is fetched, the extraRecucer would being called to set the state of Dates, if i put console.log() at extraRecer this is not executed – Biel Dec 05 '22 at 19:12
  • That slice up there... is that your `navigationSlice`? Because you are only setting that one up to be part of your state - at `state.selectedElement`. If you don't add the reducer to your store, you can dispatch all you want, the reducer will never execute. – phry Dec 05 '22 at 21:02
  • Good observation my friend im forget that, i will apply changes, this should be solved – Biel Dec 05 '22 at 22:43