ThePerplexedOne
ThePerplexedOne

Reputation: 2950

How can I access my dispatch routines from my props using TypeScript + Redux?

Take a look at the following slice I've created in TypeScript (storeSlice.ts):

import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import axios from "axios";
import { AppThunk } from "../../app/store";
import { Summoner } from "../../models/Summoner";

export interface StoreState {
    summoners: Summoner[]
}

const initialState: StoreState = {
    summoners: []
}

export const storeSlice = createSlice({
    name: 'store',
    initialState,
    reducers: {
        getSummonersSuccess: (state: StoreState, action: PayloadAction<Summoner[]>) => {
            state.summoners = action.payload;
        }
    }
});

export const { getSummonersSuccess } = storeSlice.actions;

export const getSummoners = (): AppThunk => (dispatch) => {
    axios.get("api/summoners").then((response) => {
        dispatch(getSummonersSuccess(response.data));
    });
}

export default storeSlice.reducer;

It's pretty basic. It has an initial state that is of type StoreState which contains an array of type Summoner.

Now, the component that uses this slice looks like this (Store.tsx):

import React, { Dispatch } from 'react';
import { connect } from 'react-redux';
import { getSummoners, StoreState } from './storeSlice';

interface PropState {
    store: StoreState
}

const Store = (props: StoreState) => {
    console.log("store props", props); //This contains my "getSummoners" action, but I can't access it because it's not defined in "StoreState"
    return (
        <h1>Hello!</h1>
    );
}
const mapStateToProps = (state: PropState) => {
    console.log("Store state", state);
    return { summoners: state.store.summoners };
};
const mapDispatchToProps = (dispatch: Dispatch<any>) => {
    return {
        getSummoners: dispatch(getSummoners)
    }
}
export default connect(mapStateToProps, mapDispatchToProps)(Store);

When I log the props in the component, I get the state that I've mapped with mapStateToProps, and I also get the getSummoners action that I've mapped with mapDispatchToProps.

However, I cannot actually access the getSummoners action because it is not defined in StoreState.

I do not want to have to define the actions in every default state type that I create.

Is there something I can do to be able to use the dispatch actions in my code whilst keeping TypeScript happy?

Apologies if this question doesn't make too much sense, I'm fairly new to this tech stack.

Upvotes: 0

Views: 203

Answers (1)

Linda Paiste
Linda Paiste

Reputation: 42160

In your mapDispatchToProps you are inadvertanly calling the dispatch rather than returning a function to call the dispatch from your component. Change it to:

const mapDispatchToProps = (dispatch: Dispatch<any>) => {
    return {
        getSummoners: () => dispatch(getSummoners)
    }
}

This should clear up your problems. If it doesn't, please update your post with the exact error that you are getting.

As a sidenote, this connect higher-order component with mapStateToProps and mapDispatchToProps has been around for a while and it used to be the only way to get data from the state into your component. It still works, but nowadays it is recommended that you use the newer hooks useSelector and useDispatch instead.

Upvotes: 1

Related Questions