-
typescript redux thunk 流程梳理
-
定义行为标识,此处 person 只有一个用于与服务器获取数据的行为
-
export enum personActionType { PERSON_QUERY_BASE = 'PERSON_QUERY_BASE' }
-
-
根据行为标识派发 action
// 接口 personGetInfoAction 定义了获取数据行为的 type 和 result /* export interface personGetInfoAction extends Action { type: personActionType.PERSON_QUERY_BASE result: PersonInfoResponse } */ import { personActionType, personGetInfoAction } from '../type' import { Action } from 'redux' import { ThunkAction } from 'redux-thunk' import { queryInfo } from '../../api/person' import { Dispatch } from 'redux' export interface IPersonState {} type ThunkResult<R> = ThunkAction< R, IPersonState, undefined, Action<personGetInfoAction> > const queryBaseInfo = (): ThunkResult<void> => { return async (dispatch: Dispatch) => { const result = await queryInfo() dispatch({ type: personActionType.PERSON_QUERY_BASE, result }) } }-
在代码的开始,定义了一个空的接口
IPersonState这样是为了能清楚的看懂ThunkAction接收的参数,如果有项目需要用到这个接口,可以方便的在里面添加数据类型 -
接着定义了用于简化
ThunkAction返回类型的ThunkResult<R>ThunkAction泛型一共接收四个参数R函数返回类型,在函数queryBaseInfo中,不需要返回数据,即R为 voidIPersonState可看上面的说的作用undefined这个参数用于接收额外的参数,通常以用于启用浏览器插件之类的事情,此处暂时没用,所以赋值undefined即可Action<personGetInfoAction>第四个参数是action表明了即将派发的action的类型定义,因为我知道接下来这个action是用于派发服务器返回数据的类型和结果,所以定义为Action<personGetInfoAction>
-
接着是具体派发行为的实现
- 和同步的派发
action不同,使用 redux-thunk 中间件派发异步action不是直接派发action对象,而是返回一个匿名函数,这个函数接收一个名为dispatch的参数,在匿名函数处理好异步逻辑后,由参数dispatch向 reducer 派发action对象
- 和同步的派发
-
-
reducer 接收 actionCreator 派发过来的对象,进行状态的更新
import { Reducer } from 'redux' import { personInfo, personGetInfoAction, personActionType } from '../type' export interface PersonState { baseInfo?: personInfo } let init_state: PersonState = { baseInfo: undefined } const person: Reducer<PersonState | undefined, personGetInfoAction> = ( state = init_state, action: personGetInfoAction ) => { let newState = JSON.parse(JSON.stringify(state)) switch (action.type) { case personActionType.PERSON_QUERY_BASE: let { code, data } = action.result if (code === 0) { newState.baseInfo = data } break } return newState } export default person- 前面的代码应该都能看懂,定义了
state的类型以及初始化 state - 接着定义了 类型为
Reducer名为person的函数- 类型
Reducer接收两个泛型参数- 第一个是
state,用于表明函数接收的state参数的类型以及最后返回state的类型 - 第二个参数用于表明函数从
actionCreator接收到的action
- 第一个是
- 在函数
person中的业务逻辑就不详细说明了,都是一些简单处理state之后返回新state的逻辑
- 类型
- 前面的代码应该都能看懂,定义了
-
configReducer.ts-
import { combineReducers } from 'redux' import person, { PersonState } from './person' export interface AllState { person?: PersonState } let rootReducer = combineReducers<AllState, any>({ person, course }) export default rootReducer -
这个文件主要是用于把多个
reducer合并为一个,同时也可以进行一些其他的处理,暂时我还没用到其他的处理,以后用到再更新
-
-
store.js-
import { createStore, applyMiddleware } from 'redux' import reduxThunk, { ThunkMiddleware } from 'redux-thunk' import rootReducer from './reducer/index' import { PersonState, personGetInfoAction } from './type' interface OtherState {} interface OtherAction {} type State = PersonState & OtherState type Actions = personGetInfoAction & OtherAction const store = createStore( rootReducer, applyMiddleware(reduxThunk as ThunkMiddleware<State, Actions>) ) export default store -
用于生成最后项目中用到的总的 store ,代码应该不难看懂,不就详细解析了
-
-
Info.tsximport React, { MouseEvent } from 'react' /* 第三方模块 */ import { withRouter, RouteComponentProps } from 'react-router-dom' import { connect } from 'react-redux' import { Button } from 'antd' /* 业务逻辑模块 */ import action from '../../store/action' import { exitLogin } from '../../api/person' interface propFormDispatch { queryInfo: () => void } export type ApplicationProps = RouteComponentProps & propFormDispatch class Info extends React.Component<ApplicationProps, InfoState> { async componentDidMount() { await this.props.queryInfo() } public render() { return <div>// 业务逻辑</div> } } const mapState2Props = (state: InfoState) => { return {} } const mapDispatchToProps = { queryInfo: action.person.queryBaseInfo } export default withRouter( connect( mapState2Props, mapDispatchToProps )(Info) )-
这个文件其他的东西不就解析了
-
主要用到了两个函数
mapStateToProps和mapDispatchToProps通过connect函数把redux中获取的的state挂载到props中 -
因为使用到了
react-router-dom进行组件的跳转,所以使用了RouteComponentProps把history等属性挂载到prop上
最后导出经过
widthRouter和connect高阶后的组件 -
-
App.tsximport React from 'react' import { hot } from 'react-hot-loader' import { Provider } from 'react-redux' import store from './store/index' const App: React.FC = () => { return ( <div className='App'> <Provider store={store}></Provider> </div> ) } export default hot(module)(App)- 这里主要用到
Provider把 store 挂载在react实例上 - 同时也因为使用了
react-hot-loader实现开发的热加载,最后使用了高阶处理导出组件
- 这里主要用到
-
文章就写到这里了,其实关于 redux 还有很多还没学懂的东西,也还有很多没用到,结合 typescript 使用还不熟练, 不过通过写这篇文章感觉自己对 redux-thunk 结合 typescript 理解得更清晰了。