[英]What is wrong with my approach to redux-thunk dispatch? (React, typescript, TS-2345)
我的动作创建者:
// file: redux/contest/actions.ts
import { ThunkAction } from 'redux-thunk'
import { ContestActionTypes, /* ... */ SET_CONTEST_CONFIG } from './types' ;
import { CONFIG_COLL, CONTEST_KEY, database } from '../../database'
import { RootState } from '../store';
/* ... */
export const setContestConfig: (arg0: IContestState) => ContestActionTypes =
(contestState) => ({ type: SET_CONTEST_CONFIG, payload: contestState })
export const loadContestConfig = (): ThunkAction<void, RootState, unknown, ContestActionTypes> =>
async dispatch => {
const data = await database.collection(CONFIG_COLL).doc(CONTEST_KEY).get()
dispatch(setContestConfig(data))
}
// file: redux/contest/types.ts
/* ... various action structures defined as interface ... */
export type ContestActionTypes = ISerialAction | IStringArrayAction | ITypeOnlyAction | IStringOnlyAction | ISetContestAction
这部分编译没有任何问题。
现在在我的 index.tsx 我有这个:
import React from 'react';
import ReactDOM from 'react-dom';
import { applyMiddleware, createStore } from 'redux'
import { Provider } from 'react-redux'
import thunk from 'redux-thunk'
import App from './App';
import { rootReducer } from './redux/store'
import { loadContestConfig, saveContestConfig } from './redux/contest/actions';
const store = createStore( rootReducer, applyMiddleware( thunk ) )
store.dispatch( loadContestConfig() ) // here I want to initialize state from the database
/* ... */
在 index.tsx 的第 11 行( store.dispatch(...)
)我收到错误消息 TS-2345
Argument of type 'ThunkAction<void, CombinedState<{ app: AppState; contest: IContestState; }>, unknown, ContestActionTypes>' is not assignable to parameter of type 'ISetStationAction | ISaveAppStateAction | ISerialAction | IStringArrayAction | ITypeOnlyAction | IStringOnlyAction | ISetContestAction'.
Type 'ThunkAction<void, CombinedState<{ app: AppState; contest: IContestState; }>, unknown, ContestActionTypes>' is missing the following properties from type 'ISetContestAction': type, payload TS2345
当然,作为 dispatch 传递的动作(在第一个文件中的 function loadContestConfig 中)既有type
又有payload
,所以我不知道这里有什么问题。 我按照教程进行了操作,但这无法理解,我只是看不到问题所在。
最后,我能够挖掘解决方案。 有必要指定dispatch
类型 function 因为 typescript 无法确定正确的过载。
解决方案亮点
在文件./redux/store.ts
中(商店声明)
import { combineReducers } from 'redux'
import { ThunkDispatch } from 'redux-thunk'
import { AppActionTypes } from './station/types'
import { ContestActionTypes } from './contest/types'
import { stationReducer } from './station/reducers'
import { contestStateReducer } from './contest/reducers'
export const rootReducer = combineReducers({ station: stationReducer, contest: contestStateReducer })
export type RootState = ReturnType<typeof rootReducer>
export type StoreActionTypes = AppActionTypes | ContestActionTypes
// the following line is essential - we define proper function type for dispatch with thunk
export type DispatchFunctionType = ThunkDispatch<RootState, undefined, StoreActionTypes>
在文件./index.tsx
(React 应用程序主 TSX 文件)
import React from 'react';
import ReactDOM from 'react-dom';
import { applyMiddleware, createStore} from 'redux'
import { Provider } from 'react-redux'
import thunk from 'redux-thunk'
import App from './App';
import { DispatchFunctionType, rootReducer, RootState } from './redux/store'
import { loadContestConfig } from './redux/contest/actions';
import { loadStation } from './redux/station/actions';
const store = createStore( rootReducer,
applyMiddleware<DispatchFunctionType, RootState>( thunk ) ) // <- this is essential
store.dispatch(loadContestConfig()) // here I had TS2345 before, now no more problems
store.dispatch(loadStation()) // - dtto -
只要dispatch
function 作为参数传递,就必须声明相同的dispatch
function 类型。
示例:在文件StationDataModal.tsx
中
...
import { DispatchFunctionType, RootState } from "./redux/store"
...
// the following mapping function also caused TS-2345
// when dispatch type was not declared explicitly
const mapDispatchToProps = ( dispatch: DispatchFunctionType ) => {
return {
setContestName: ( name: string ) => {
dispatch(setContestName( name ))
dispatch(saveContestConfig())
},
setStationData: ( mycall: string, mywwloc: string ) => {
dispatch(setStation( { mycall, mywwloc } ))
dispatch(saveStation())
}
}
}
...
class StationDataModal extends React.Component<StationDataProps> {
/* component definition ... */
}
export default connect( mapStateToProps, mapDispatchToProps ) (StationDataModal)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.