Search code examples
reactjstypescriptredux

error on execute async function on redux and typescript


I am having problems when I execute some async functions inside the store. For my application, I am using React, Redux and Typescript

If you look below, I execute a fetch and then I dispatch 3 functions.

First: activate the message visibility to true; Second: to change the text message; Third: to deactivate the message visibility after 5 seconds (async function)

.then(response => {
            if (response.ok) {
                dispatch({ type: 'LOGIN' });
            } else {
                return response.json().then(data => {
                    dispatch({ type: 'TOGGLE_VISIBILITY'});
                    dispatch({ type: 'MESSAGE_ALERT', payload: data.detail});
                    dispatch(hideMessageAlert()); // Dispatching the new action creator
                });
            }
        })

However I got this kind of error when I write the third dispatch

"Argument of type '(dispatch: Dispatch) => void' is not assignable to parameter of type 'AnyAction'."

This is my code from my store.tsx and the types.tsx. Is there something that I should do?

import { configureStore, Dispatch } from '@reduxjs/toolkit';
import { AppState } from './types';
import { AnyAction } from 'redux';

// data()
const initialState: AppState = {
    loggedIn: false,
    isVisible: false,
    messageAlert: '',
};

// methods()
interface Action extends AnyAction {
    type: 'LOGIN' | 'LOGOUT' | 'TOGGLE_VISIBILITY' | 'MESSAGE_ALERT';
    payload?: string | boolean
  }


// Adding a new action creator that dispatches a TOGGLE_VISIBILITY action with false payload after 5 seconds
const hideMessageAlert = () => (dispatch: Dispatch<Action>) => {
    setTimeout(() => {
      dispatch({ type: 'TOGGLE_VISIBILITY', payload: false });
    }, 5000);
};
  

function rootReducer(state = initialState, action: Action): AppState {
    switch (action.type) {
        case 'LOGIN':
            return {
                ...state,
                loggedIn: true,
            };
        case 'LOGOUT':
            return {
                ...state,
                loggedIn: false,
            };
        case 'TOGGLE_VISIBILITY':
            console.log(action.payload);
            return {
                ...state,
                isVisible: !state.isVisible,
            };
        case 'MESSAGE_ALERT':
            return {
                ...state,
                messageAlert:`${action.payload}`,
            };
        default:
            return state;
    }
}

const store = configureStore({
    reducer: rootReducer,
    preloadedState: initialState,
});

export { hideMessageAlert, store,};

types.tsx

export interface AppState {
    loggedIn: boolean;
    isVisible: boolean;
    messageAlert: string;
}

Solution

  • If you can't write that any other way, the only solution I see is accepting an action of type Action | (dispatch: Dispatch) => void

    function rootReducer(
      state = initialState, 
      action: Action | (dispatch: Dispatch) => void
      ): AppState {
      // ...
    }
    

    Or you could just call the setTimeout inside the promise chain:

    .then(response => {
                if (response.ok) {
                    dispatch({ type: 'LOGIN' });
                } else {
                    return response.json().then(data => {
                        dispatch({ type: 'TOGGLE_VISIBILITY'});
                        dispatch({ type: 'MESSAGE_ALERT', payload: data.detail});
                        setTimeout(() => {
                          dispatch({ type: 'TOGGLE_VISIBILITY', payload: false });
                        }, 5000);
                    });
                }
            })