简体   繁体   English

我的 redux-thunk 调度方法有什么问题? (反应,typescript,TS-2345)

[英]What is wrong with my approach to redux-thunk dispatch? (React, typescript, TS-2345)

My action creators:我的动作创建者:

// 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 

This part compiles without any problems.这部分编译没有任何问题。

Now in my index.tsx I have this:现在在我的 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
/* ... */

And on the line 11 of index.tsx ( store.dispatch(...) ) I get error message TS-2345在 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

Of course, the action passed as to dispatch (in function loadContestConfig in the first file) has both type and payload , so I have no idea what's wrong here.当然,作为 dispatch 传递的动作(在第一个文件中的 function loadContestConfig 中)既有type又有payload ,所以我不知道这里有什么问题。 I followed tutorials but this is incomprehensible, I just can't see the problem.我按照教程进行了操作,但这无法理解,我只是看不到问题所在。

Finally, I was able to dig the solution.最后,我能够挖掘解决方案。 It is necessary to specify the type of dispatch function because typescript is unable to determine the correct overload.有必要指定dispatch类型 function 因为 typescript 无法确定正确的过载。

Solution highlights解决方案亮点

in file ./redux/store.ts (store declarations)在文件./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>

in file ./index.tsx (React app main TSX file)在文件./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 -

The same dispatch function type must be declared wherever dispatch function is passed as parameter.只要dispatch function 作为参数传递,就必须声明相同的dispatch function 类型。

Example: in file StationDataModal.tsx示例:在文件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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM