You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/** * The dispatch method as modified by React-Thunk; overloaded so that you can * dispatch: * - standard (object) actions: `dispatch()` returns the action itself * - thunk actions: `dispatch()` returns the thunk's return value * * @template TState The redux state * @template TExtraThunkArg The extra argument passed to the inner function of * thunks (if specified when setting up the Thunk middleware) * @template TBasicAction The (non-thunk) actions that can be dispatched. */exportinterfaceThunkDispatch<TState,TExtraThunkArg,TBasicActionextendsAction>{<TReturnType>(thunkAction: ThunkAction<TReturnType,TState,TExtraThunkArg,TBasicAction>,): TReturnType;<AextendsTBasicAction>(action: A): A;// This overload is the union of the two above (see TS issue #14107).<TReturnType,TActionextendsTBasicAction>(action:
|TAction|ThunkAction<TReturnType,TState,TExtraThunkArg,TBasicAction>,): TAction|TReturnType;}
/** * A "thunk" action (a callback function that can be dispatched to the Redux * store.) * * Also known as the "thunk inner function", when used with the typical pattern * of an action creator function that returns a thunk action. * * @template TReturnType The return type of the thunk's inner function * @template TState The redux state * @template TExtraThunkARg Optional extra argument passed to the inner function * (if specified when setting up the Thunk middleware) * @template TBasicAction The (non-thunk) actions that can be dispatched. */exporttypeThunkAction<TReturnType,TState,TExtraThunkArg,TBasicActionextendsAction>=(dispatch: ThunkDispatch<TState,TExtraThunkArg,TBasicAction>,getState: ()=>TState,extraArgument: TExtraThunkArg,)=>TReturnType;
整理一下参数类型和代表的意思:
ThunkAction 指代的是一个 thunk action, 或者也叫做 thunk inner function
前言
上一篇文章讲了讲如何用 TypeScript + Redux 实现
Loading
切片部分的状态, 这篇文章主要想聊一聊关于Todo
和Filter
这两个切片状态的具体实现, 以及关于 Redux Thunk 与 TypeScript 的结合使用.想跳过文章直接看代码的: 完整代码
最后的效果:
Todo
首先思考一下
Todo
应该是怎样的状态, 以及可能需要涉及到的action
.页面上的每一个
todo
实例都对应一个状态, 合起来总的状态就应该是一个数组, 这也应该是reducer
最后返回的状态形式. 同时, 考虑action
, 应该有以下几种操作:todos
todo
todo
todo
todo
这里需要注意的是, 所有的操作都需要和服务端交互, 因此我们的
action
是 "不纯的", 涉及到异步操作. 这里会使用 Redux Thunk 这个库来加持一下.Action Creator
写法也会变成对应的Thunk
形式的Action Creator
types
每一个
todo
的状态类型应该如下:id
一般是服务端返回的, 不做过多解释.text
是todo
的具体内容,done
属性描述这个todo
是否被完成actions
actionTypes
还是和之前一样, 在写
action
之前先写好对应的类型, 包括每一个action
的type
属性根据上面的描述,
type
有如下几种:对应的
actionTypes
, 就可以引用写好的常量类型了:actionCreators
这里需要注意,
todo
部分的actions
分为同步和异步, 先来看同步的:同步部分没什么好说的, 核心是异步部分, 我们用 Redux Thunk 这个中间件帮助我们编写 Thunk 类型的
Action
. 这种Action
不再是纯的, 同时这个Action
是一个函数而不再是一个对象, 因为存在往服务端请求数据的副作用逻辑. 这也是 Redux 和 Flow 的一个小区别(Flow 规定Action
必须是纯的)首先我们需要配置一下
thunk
, 以及初始化一下store
Thunk Action Creator
不考虑类型, 如果纯用 JavaScript 写一个
Thunk ActionCreator
, 如下:这里的
baseURL
在我第一章有说, 用了 mock api 模拟后端的数据, 具体地址可以看文章或者看源码, 同时为了方便, 我直接用浏览器原生的fetch
做 http 请求了, 当然用axios
等别的库也是可以的关于这个函数简单说明一下, 这里的
setTodosRequest
就是一个Thunk ActionCreator
, 返回的(dispatch) => {}
就是我们需要的Thunk Action
, 可以看到这个Thunk Action
是一个函数, Redux Thunk 允许我们将 Action 写成这种模式下面为这个
Thunk ActionCreator
添加类型, Redux Thunk 导出的包里有提供两个很重要的泛型类型:首先是
ThunkDispatch
, 具体定义如下至于具体怎么实现我不关心, 我关心的是这个东西是啥以及这个泛型接受哪些类型参数, 整理一下如下:
dispatch
类型是由 Redux Thunk 修改过的类型, 你可以用它dispatch
:action
(一个对象),dispatch()
函数返回这个对象action
本身thunk action
(一个函数),dispatch()
函数返回这个thunk action
函数的返回值TState
,TExtraThunkArg
,TBasicAction
TState
: Redux store 的状态(RootState
)TExtraThunkArg
: 初始化 thunk 中间件时, 传个 thunk 的额外参数(这个项目我们没用到)TBasicAction
: 非 Thunk 类型的 action, 即标准的对象 action 类型再看一下
ThunkAction
:整理一下参数类型和代表的意思:
ThunkAction
指代的是一个thunk action
, 或者也叫做thunk inner function
TReturnType
,TState
,TExtraThunkArg
,TBasicAction
TReturnType
: 这个thunk action
函数最后的返回值TState
: Redux store 的状态(RootState
)TExtraThunkArg
: 初始化 thunk 中间件时, 传个 thunk 的额外参数(这个项目我们没用到)TBasicAction
: 非 Thunk 类型的 action, 即标准的对象 action 类型看完发现, 其实
ThunkAction
和ThunkDispatch
真的很像, 对应到具体的参数类型:TState
我们是有的, 即之前写过的RootState
TExtraThunkArg
我们没有用到, 可以直接给void
或者unknown
TBasicAction
我们还没定义, 我见过有用Redux
的AnyAction
来替代, 但是AnyAction
这个 any 有点过分...我搜索了一下没找到官方的最佳实践, 就打算用所有的 Redux 的 Action 类型集合以及, Redux 官网的 Usage with Redux Thunk 其实已经有写怎么配置类型了. 现在需要做的事情其实就很简单:
RootAction
类型, 为所有的非 Thunk 类型的Action
的类型的集合ThunkDispatch
这个泛型传入正确类型ThunkAction
这个泛型传入正确类型store
部分的代码如下:为了方便, 这里给了两个 alias, 也是根据官网来的, 分别为
AppDispatch
和AppThunk
现在可以完善之前的
Thunk ActionCreator
的类型了:这里注意一下, 由于我们的
thunk action
, 是有返回值的, 这里是return fetch()
返回的是一个promise
, 不过这个promise
并没有resolve
任何值, 所以即为Promise<void>
最后完善一下所有的
actionCreator
:这里说一点题外话, 其实 Redux 不用 Thunk 这种 middleware 来做异步请求也是可以的, 但是为啥还会有
Redux Thunk
这些库存在呢. 具体细节我之前写过一个回答, 有兴趣可以看一看: redux中间件对于异步action的意义是什么?reducer
编写完复杂的
ActionCreator
,reducer
相比就简单很多了, 这里直接贴代码了:写完
reducer
记得在store
中写入combineReducer()
selectors
最后是
selectors
, 由于这部分是需要和filter
切片进行协作,filter
部分下面会讲, 这里先贴代码, 最后可以再回顾todo 部分基本完成了, 最后有一个点, Redux 文档中其实一直有提到, 不过之前我一直忽略, 这次看了 redux 文档到底说了什么(上) 文章才有注意到, 就是 Normalizing State Shape. 这部分是关于性能优化的, 我自己的项目包括实习的公司项目其实从来都没有做过这一部分, 因此实战经验为 0. 有兴趣的可以去看看
Filter
最后一个状态切片
filter
, 这部分主要是为了帮助选择展示的 todo 部分. 由于这部分较为简单, 和loading
部分类似, 居多为代码的罗列types
回顾之前想要实现的效果, TodoApp 底部是一个类似 tab 的组件, 点击展示不同状态的 todos. 总共是三部分:
编写一下具体的类型:
actions
actionTypes
actions
reducer
Store
最后将所有
store
底下的actions
,reducers
集成一下,store
文件如下:总结
至此所有关于
store
部分的代码已经全部完成了. 下一篇文章也就是最后一篇文章会完成 UI 部分, 讲一讲关于React
,Hooks
和TypeScript
以及React Redux
里相关Hooks
的使用参考
The text was updated successfully, but these errors were encountered: