redux异步action_异步 Action

异步 Action

在 基础教程 中,我们创建了一个简单的 todo 应用。它只有同步操作。每当 dispatch action 时,state 会被立即更新。

在本教程中,我们将开发一个不同的,异步的应用。它将使用 Reddit API 来获取并显示指定 subreddit 下的帖子列表。那么 Redux 究竟是如何处理异步数据流的呢?

Action

当调用异步 API 时,有两个非常关键的时刻:发起请求的时刻,和接收到响应的时刻(也可能是超时)。

这两个时刻都可能会更改应用的 state;为此,你需要 dispatch 普通的同步 action。一般情况下,每个 API 请求都需要 dispatch 至少三种 action:

一种通知 reducer 请求开始的 action。

对于这种 action,reducer 可能会切换一下 state 中的 isFetching 标记。以此来告诉 UI 来显示加载界面。

一种通知 reducer 请求成功的 action。

对于这种 action,reducer 可能会把接收到的新数据合并到 state 中,并重置 isFetching。UI 则会隐藏加载界面,并显示接收到的数据。

一种通知 reducer 请求失败的 action。

对于这种 action,reducer 可能会重置 isFetching。另外,有些 reducer 会保存这些失败信息,并在 UI 里显示出来。

为了区分这三种 action,可能在 action 里添加一个专门的 status 字段作为标记位:

{ type: 'FETCH_POSTS' }

{ type: 'FETCH_POSTS', status: 'error', error: 'Oops' }

{ type: 'FETCH_POSTS', status: 'success', response: { ... } }

又或者为它们定义不同的 type:

{ type: 'FETCH_POSTS_REQUEST' }

{ type: 'FETCH_POSTS_FAILURE', error: 'Oops' }

{ type: 'FETCH_POSTS_SUCCESS', response: { ... } }

究竟使用带有标记位的同一个 action,还是多个 action type 呢,完全取决于你。这应该是你的团队共同达成的约定。使用多个 type 会降低犯错误的机率,但是如果你使用像 redux-actions 这类的辅助库来生成 action 创建函数和 reducer 的话,这就完全不是问题了。

无论使用哪种约定,一定要在整个应用中保持统一。

在本教程中,我们将使用不同的 type 来做。

同步 Action 创建函数(Action Creator)

下面先定义几个同步的 action 类型 和 action 创建函数。比如,用户可以选择要显示的 subreddit:

actions.js

export const SELECT_SUBREDDIT = 'SELECT_SUBREDDIT'

export function selectSubreddit(subreddit) {

return {

type: SELECT_SUBREDDIT,

subreddit

}

}

也可以按 "刷新" 按钮来更新它:

export const INVALIDATE_SUBREDDIT = 'INVALIDATE_SUBREDDIT'

export function invalidatesubreddit(subreddit) {

return {

type: INVALIDATE_SUBREDDIT,

subreddit

}

}

这些是用户操作来控制的 action。也有另外一类 action,是由网络请求来控制。后面会介绍如何使用它们,现在,我们只是来定义它们。

当需要获取指定 subreddit 的帖子的时候,需要 dispatch REQUEST_POSTS action:

export const REQUEST_POSTS = 'REQUEST_POSTS'

export function requestPosts(subreddit) {

return {

type: REQUEST_POSTS,

subreddit

}

}

把 REQUEST_POSTS 和 SELECT_SUBREDDIT 或 INVALIDATE_SUBREDDIT 分开很重要。虽然它们的发生有先后顺序,但随着应用变得复杂,有些用户操作(比如,预加载最流行的 subreddit,或者一段时间后自动刷新过期数据)后需要马上请求数据。路由变化时也可能需要请求数据,所以一开始如果把请求数据和特定的 UI 事件耦合到一起是不明智的。

最后,当收到请求响应时,我们会 dispatch RECEIVE_POSTS:

export const RECEIVE_POSTS = 'RECEIVE_POSTS'

export function receivePosts(subreddit, json) {

return {

type: RECEIVE_POSTS,

subreddit,

posts: json.data.children.map(child => child.data),

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值