Reputation: 2950
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
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