dark123
dark123

Reputation: 23

Problem with Redux Thunk ( could not run function in reducer)

I have a problem with redux-thunk (redux-toolkit) , when I dispatch action logIn, console.log is working but this function Auth in apiInstance.ts file is not working

Here are my set up store and reducer

// my config's store
import { ThunkAction, thunk } from "redux-thunk";
import { Action, configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
import rootReducer from "../reducer/index.ts";

const store = configureStore({
  reducer: rootReducer,
  middleware: [...getDefaultMiddleware(), thunk],
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export type AppThunk = ThunkAction<void, RootState, null, Action<any>>;
export default store;

// my store 
import { combineReducers } from "redux";
import AuthReducer from "./auth/index.ts";
import PathVariableReducer from "./pathVariable/index.ts";
import codeRunner from "./codeRunner/index.ts";
import toastMessage from "./toastMessage/index.ts";
import dataDefine from "./dataDefine.ts";
const rootReducer = combineReducers({
  AuthReducer,
  PathVariableReducer,
  codeRunner,
  toastMessage,
  dataDefine,
});

export default rootReducer;

// my reducer

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

import {
  Auth,
  LogOut,
  ResetPasswordEmail,
  UpdateInfor,
} from "../../../service/apiInstance";


const AuthReducer = createSlice({
  name: "auth",
  initialState: {},
  reducers: {
    logIn: (state, action) => {
      console.log("test") // working
      Auth(action.payload, "login"); // not working
    },
    logOut: (state, action) => LogOut(),
    register: (state, action) => Auth(action.payload, "register"),
    forgotPassword: (state, action) =>
      ResetPasswordEmail({ email: action.payload }),
    resetPassword: (state, action) =>
      ResetPasswordEmail({
        oldPassword: action.payload,
        newPassword: action.payload,
      }),
    updateInfor: (state, action) => UpdateInfor(action.payload),
  },
});

and this is my function Auth in apiInstance.ts

// not working
import axios from "axios";
import { TOAST_MESSAGE } from "../redux/reducer/toastMessage";
import { Dispatch } from "redux";
import { AppDispatch, AppThunk } from "../redux/store";
import { getPostSuccess } from "../redux/reducer/dataDefine";

export const Auth = (req: object, auth: string): AppThunk => async ( // my function
  dispatch: AppDispatch
) => {
  console.log("test successful");
  await fetchCSRFToken();
  try {
    const response = await axiosInstance.post(`/${auth}`, req);
    localStorage.setItem("login", "true");
    localStorage.setItem("name", JSON.stringify(response.data.name));
    localStorage.setItem("email", JSON.stringify(response.data.email));
    window.location.replace("/");
    console.log(response.data);
  } catch (error) {
    dispatch(getPostSuccess);
    dispatch(
      TOAST_MESSAGE({
        type: "error",
        content: error,
        duration: 5,
      })
    );
    throw new Error("Authentication failed");
  }
};

I'm trying any case but it's not working, so what should I do in this case?

Upvotes: 1

Views: 80

Answers (2)

Adam Morsi
Adam Morsi

Reputation: 499

You are not using redux toolkit correctly:

1- redux thunk is part of redux toolkit by default which means you don’t need to add it yourself, here’s my store setup: store.ts

import { configureStore } from '@reduxjs/toolkit';
//root reducer
import { reduxSlices } from './reduxSlices';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';

const isDevelopment = process.env.NODE_ENV === 'development';

const store = configureStore({
  reducer: reduxSlices,
  devTools: isDevelopment,
  middleware: (getDefaultMiddleware) => {
    if (isDevelopment) {
      const { logger } = require('redux-logger');

      return getDefaultMiddleware().concat(logger);
    }

    return getDefaultMiddleware();
  },
});

//type of your store if you need to use it somewhere
export type ToolkitStore = typeof store;
export type RootState = ReturnType<typeof store.getState>;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
export type AppDispatch = typeof store.dispatch;
export const useAppDispatch: () => AppDispatch = useDispatch;

export default store;

2- reduxSlices.ts:

import { combineReducers } from '@reduxjs/toolkit';
// slices
/* PLOP_INJECT_IMPORT */
import AuthReducer from './auth/index.ts';
import PathVariableReducer from './pathVariable/index.ts';
import codeRunner from './codeRunner/index.ts';
import toastMessage from './toastMessage/index.ts';
import dataDefine from './dataDefine.ts';

export const slices = combineReducers({
  /* PLOP_INJECT_REDUCER_SLICE */
  AuthReducer,
  PathVariableReducer,
  codeRunner,
  toastMessage,
  dataDefine,
});

export const reduxSlices = (state: any, action: any) => {
  /*reset redux slices except one property of a slice*/
  /*if (action.type === 'user/logoutUser') {
    // Preserve the state of user.featureFlags
    const featureFlags = state.user.featureFlags;

    // Reset the user slice to its initial state except featureFlags
    const userSlice = updateObject(userInitialState, { featureFlags });

    // Reset redux state
    state = undefined;

    state = updateObject(state, { user: userSlice });
  }*/

  /*reset all redux slices*/
  /*if (action.type === 'user/logoutUser') {
    // Reset redux state
    state = undefined;
  }*/

  return slices(state, action);
};

3- In apiInstance.ts you need to use createAsyncThunk from redux toolkit:

export const loginUser = createAsyncThunk('loginUser', async () => {
  await fetchCSRFToken();
  const response = await axiosInstance.post(`/${auth}`, req);
  localStorage.setItem('login', 'true');
  localStorage.setItem('name', JSON.stringify(response.data.name));
  localStorage.setItem('email', JSON.stringify(response.data.email));
  window.location.replace('/');
});

4- In your reducer:

const AuthReducer = createSlice({
  name: 'auth',
  initialState: {
    isLoggingUser: false,
  },
  reducers: {},
  extraReducers: (builder) => {
    //loginUser
    builder
      .addCase(loginUser.pending, (state) => {
        state.isLoggingUser = true;
      })
      .addCase(loginUser.fulfilled, (state) => {
        state.isLoggingUser = false;
      })
      .addCase(loginUser.rejected, (state) => {
        state.isLoggingUser = false;
        dispatch(
          TOAST_MESSAGE({
            type: "error",
            content: error,
            duration: 5,
          })
        );
      });
  },
});

Upvotes: 0

Carsten Codes
Carsten Codes

Reputation: 131

Have you tried moving the Auth call outside the reducer logic and dispatch it from the component where you handle login?

In your logIn reducer, you are directly calling the Auth() function, instead you can try to dispatch it from within a component:

// In a component or a separate action creator
dispatch(Auth(payload, "login"));

Upvotes: 0

Related Questions