使用 Redux 获取数据时如何避免竞争条件? [英] How to avoid race conditions when fetching data with Redux?

查看:30
本文介绍了使用 Redux 获取数据时如何避免竞争条件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个异步获取对象的操作,我们称之为getPostDetails,它接受一个参数来表示要获取的帖子一个身份证.用户会看到一个帖子列表,可以点击一个来获取一些详细信息.

We have an action that fetches an object async, let's call it getPostDetails, that takes a parameter of which post to fetch by an id. The user is presented with a list of posts and can click on one to get some details.

如果用户点击帖子 #1",我们会发送一个 GET_POST 操作,它可能看起来像这样.

If a user clicks on "Post #1", we dispatch a GET_POST action which might look something like this.

const getPostDetails = (id) => ({
  type: c.GET_POST_DETAILS,
  promise: (http) => http.get(`http://example.com/posts/#${id}`),
  returnKey: 'facebookData'
})

这是由中间件获取的,它向承诺添加一个成功处理程序,它将调用类似的操作GET_POST__OK 使用反序列化的 JSON 对象.减速器看到这个对象并将它应用到商店.一个典型的__OK 减速器看起来像这样.

This is picked up by a middleware, which adds a success handler to the promise, which will call an action like GET_POST__OK with the deserialized JSON object. The reducer sees this object and applies it to a store. A typical __OK reducer looks like this.

[c.GET_ALL__OK]: (state, response) => assign(state, {
  currentPost: response.postDetails
})

稍后我们有一个组件,它查看 currentPost 并显示当前帖子的详细信息.

Later down the line we have a component that looks at currentPost and displays the details for the current post.

然而,我们有一个竞争条件.如果用户一个接一个地提交两个 GET_POST_DETAILS 操作,则有不保证我们收到 __OK 动作的顺序,如果第二个 http 请求在第一个之前完成,则状态将变得不正确.

However, we have a race condition. If a user submits two GET_POST_DETAILS actions one right after the other, there is no guarantee what order we recieve the __OK actions in, if the second http request finishes before the first, the state will become incorrect.

    Action                   => Result
    ---------------------------------------------------------------------------------
|T| User Clicks Post #1      => GET_POST for #1 dispatched => Http Request #1 pending
|i| User Clicks Post #2      => GET_POST for #2 dispatched => Http Request #2 pending
|m| Http Request #2 Resolves => Results for #2 added to state
|e| Http Request #1 Resolves => Results for #1 added to state
 V

我们如何确保用户点击的最后一个项目总是优先?

How can we make sure the last item the user clicked always will take priority?

推荐答案

问题是由于状态组织不理想造成的.

The problem is due to suboptimal state organization.

在 Redux 应用中,像 currentPost 这样的状态键通常是一种反模式.如果您每次导航到另一个页面时都必须重置"状态,那么您将失去一个 主要好处Redux(或 Flux):缓存.例如,如果任何导航重置状态并重新获取数据,您将无法再立即导航回去.

In a Redux app, state keys like currentPost are usually an anti-pattern. If you have to "reset" the state every time you navigate to another page, you lost one of the main benefits of Redux (or Flux): caching. For example, you can no longer navigate back instantly if any navigation resets the state and refetches the data.

存储此信息的更好方法是将 postsByIdcurrentPostId 分开:

A better way to store this information would be to separate postsById and currentPostId:

{
  currentPostId: 1,
  postsById: {
    1: { ... },
    2: { ... },
    3: { ... }
  }
}

现在您可以随心所欲地同时获取任意数量的帖子,并将它们独立地合并到postsById 缓存中,而无需担心获取的帖子是否是当前帖子.

Now you can fetch as many posts at the same time as you like, and independently merge them into the postsById cache without worrying whether the fetched post is the current one.

在你的组件内部,你总是会读取 state.postsById[state.currentPostId],或者更好的是,从 reducer 文件中导出 getCurrentPost(state) 选择器,以便组件不依赖于特定的状态形状.

Inside your component, you would always read state.postsById[state.currentPostId], or better, export getCurrentPost(state) selector from the reducer file so that the component doesn’t depend on specific state shape.

现在没有竞争条件并且你有一个帖子缓存,所以你回去时不需要重新获取.稍后,如果您希望从 URL 栏控制当前帖子,您可以从 Redux 状态中完全删除 currentPostId,而是从您的路由器读取它——其余的逻辑将保持不变.

Now there are no race conditions and you have a cache of posts so you don’t need to refetch when you go back. Later if you want the current post to be controlled from the URL bar, you can remove currentPostId from Redux state completely, and instead read it from your router—the rest of the logic would stay the same.

虽然这并不完全相同,但我碰巧有另一个具有类似问题的示例.查看之前的代码代码之后.这与您的问题完全不一样,但希望它展示了国家组织如何帮助避免竞争条件和不一致的道具.

While this isn’t strictly the same, I happen to have another example with a similar problem. Check out the code before and the code after. It’s not quite the same as your question, but hopefully it shows how state organization can help avoid race conditions and inconsistent props.

我还录制了一个免费视频系列来解释这些主题,因此您可能想要查看.

I also recorded a free video series that explains these topics so you might want to check it out.

这篇关于使用 Redux 获取数据时如何避免竞争条件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆