Home > Mobile >  Argument of type '(dispatch: Dispatch<ShopDispatchTypes>) => Promise<void>'
Argument of type '(dispatch: Dispatch<ShopDispatchTypes>) => Promise<void>'

Time:05-27

Error:

Argument of type '(dispatch: Dispatch<ShopDispatchTypes>) => Promise<void>' is not assignable to parameter of type 'AnyAction'.
useEffect(() => {
  dispatch(GetShops());
}, []);

I am trying to implement redux-thunk using Typescript. I have created simple shopping card app using react,typescript and redux-thunk but getting above issue. Below is my code snippet’s. Feel free to ask if you need more info.

shops.actionTypes.ts

export const SHOP_LOAD_START = 'SHOP_LOAD_START';
export const SHOP_LOAD_SUCCESS = 'SHOP_LOAD_SUCCESS';
export const SHOP_LOAD_ERROR = 'SHOP_LOAD_ERROR';

export type Shop = {
 id: string;
 name: string;
};

export type ShopType = {
 shops: Shop[];
};

export interface ShopLoadStart {
 type: typeof SHOP_LOAD_START;
}

export interface ShopLoadError {
 type: typeof SHOP_LOAD_ERROR;
}

export interface ShopLoadSuccess {
 type: typeof SHOP_LOAD_SUCCESS;
 payload: ShopType;
}

export type ShopDispatchTypes = ShopLoadStart | ShopLoadError | ShopLoadSuccess;

shops.action.ts

export const GetShops = () => async (dispatch: Dispatch<ShopDispatchTypes>) => {
  try {
    dispatch({
      type: SHOP_LOAD_START,
    });

    const res = await http.get('d9b45894-2549-4e34-9486-7668c2e000a0');

    dispatch({
      type: SHOP_LOAD_SUCCESS,
      payload: res.data,
    });
  } catch (e) {
    dispatch({
      type: SHOP_LOAD_ERROR,
    });
  }
};

shops.reducer.ts

export interface IDefaultState {
  isLoading: boolean;
  shop?: ShopType;
}

export const defaultState: IDefaultState = {
  isLoading: false,
};

const shopsReducer = (
  state: IDefaultState = defaultState,
  action: ShopDispatchTypes
): IDefaultState => {
  switch (action.type) {
    case SHOP_LOAD_START:
      return {
        ...state,
        isLoading: true,
      };
    case SHOP_LOAD_SUCCESS:
      return {
        ...state,
        isLoading: false,
        shop: action.payload,
      };
    case SHOP_LOAD_ERROR:
      return {
        ...state,
        isLoading: false,
      };
    default:
      return state;
  }
};

export default shopsReducer;

store.ts

const Store = createStore(
  rootReducer,
  composeWithDevTools(applyMiddleware(thunk))
);

export type RootStore = ReturnType<typeof rootReducer>;

export default Store;

ShoppingCard.tsx

const ShoppingCard: React.FC<IShoppingCard> = (props: IShoppingCard) => {
  const { label } = props;

  const dispatch = useDispatch();

  const shopsData = useSelector((state: RootStore) => state.shop);

  useEffect(() => {
    dispatch(GetShops()); //Getting error here
  }, []);

}

If I am doing anything wrong please let me know. Spent several hours for that but didn't find any solution.

GitHub: Source code link

CodePudding user response:

The problem is that const dispatch = useDispatch(); only knows about the basic Dispatch type from the redux core. That Dispatch type does not know that thunks exist - it only accepts plain action objects. So, when you try to dispatch a thunk, it (correctly) errors.

The fix is to follow our "Usage with TS" guidelines for correctly inferring an AppDispatch type from store.dispatch, and then defining pre-typed hooks that have the thunk types baked in:

https://redux.js.org/tutorials/typescript-quick-start

Also, while it's not directly related to the question: the "hand-written" Redux patterns you're using are very outdated, and not how we want people using Redux today. Instead, we now teach a set of "modern Redux" patterns that are much easier to learn and use - Redux Toolkit for logic React-Redux hooks. Our official docs tutorials teach RTK hooks as standard Redux today, but most other tutorials are very outdated. See our official docs to learn how to use Redux Toolkit, which will drastically simplify the code you've got there:

https://redux.js.org/tutorials/index

  • Related