Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/452.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在使用Redux获取数据时避免竞争条件?_Javascript_Redux - Fatal编程技术网

Javascript 如何在使用Redux获取数据时避免竞争条件?

Javascript 如何在使用Redux获取数据时避免竞争条件?,javascript,redux,Javascript,Redux,我们有一个异步获取对象的操作,我们称之为getPostDetails,它接受一个参数,该参数表示通过哪个post获取 一个id。用户将看到一个帖子列表,可以单击其中一个来获取详细信息 如果用户单击“Post#1”,我们将发送一个GET_Post操作,该操作可能如下所示 const getPostDetails = (id) => ({ type: c.GET_POST_DETAILS, promise: (http) => http.get(`http://example.c

我们有一个异步获取对象的操作,我们称之为
getPostDetails
,它接受一个参数,该参数表示通过哪个post获取 一个id。用户将看到一个帖子列表,可以单击其中一个来获取详细信息

如果用户单击“Post#1”,我们将发送一个
GET_Post
操作,该操作可能如下所示

const getPostDetails = (id) => ({
  type: c.GET_POST_DETAILS,
  promise: (http) => http.get(`http://example.com/posts/#${id}`),
  returnKey: 'facebookData'
})
[c.GET_ALL__OK]: (state, response) => assign(state, {
  currentPost: response.postDetails
})
这是由一个中间件实现的,它在promise中添加了一个成功处理程序,该处理程序将调用类似于
GET\u POST\u OK
使用反序列化的JSON对象。reducer会看到此对象并将其应用于存储。典型的
\uuu好的
减速器如下所示

const getPostDetails = (id) => ({
  type: c.GET_POST_DETAILS,
  promise: (http) => http.get(`http://example.com/posts/#${id}`),
  returnKey: 'facebookData'
})
[c.GET_ALL__OK]: (state, response) => assign(state, {
  currentPost: response.postDetails
})
稍后,我们将看到一个组件,它查看
currentPost
,并显示当前帖子的详细信息

然而,我们有一个比赛条件。如果用户一个接一个地提交两个
GET\u POST\u DETAILS
操作,则 如果第二个http请求在第一个http请求之前完成,则 状态将变得不正确

    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

如何确保用户始终单击的最后一项具有优先权?

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

在Redux应用程序中,像
currentPost
这样的状态键通常是反模式的。如果每次导航到另一个页面时都必须“重置”状态,则会丢失以下选项之一:缓存。例如,如果任何导航重置状态并重新提取数据,则无法立即返回

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

{
  currentPostId: 1,
  postsById: {
    1: { ... },
    2: { ... },
    3: { ... }
  }
}
现在,您可以在同一时间获取任意数量的帖子,并将它们独立地合并到
postsbyd
缓存中,而不必担心获取的帖子是否是当前帖子

在组件内部,您将始终读取
state.postsbyd[state.currentPostId]
,或者更好地从reducer文件中导出
getCurrentPost(state)
选择器,以便组件不依赖于特定的状态形状

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


虽然严格来说这并不相同,但我碰巧有另一个类似问题的例子。查看和。这和你的问题不太一样,但希望它能说明国家组织如何帮助避免种族状况和不一致的道具


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

丹的解决方案可能更好,但另一个解决方案是在第二个请求开始时中止第一个请求

您可以通过将动作创建者拆分为一个异步创建者来完成此操作,该创建者可以从存储中读取并分派其他动作,redux thunk允许您这样做

异步操作创建者应该做的第一件事是检查存储区中是否存在承诺,如果存在承诺,则将其中止。如果没有,它可以发出请求,并发送一个“request begins”操作,该操作包含promise对象,该对象将存储以供下次使用


这样,只有最近创建的承诺才能解决问题。当有人这样做时,您可以使用接收到的数据发送一个成功操作。如果承诺因某种原因被拒绝,您还可以发送错误操作

请注意,我们不建议将承诺存储在状态中。理想情况下,它应该是可序列化的。然而,我确实描述了您在中建议的方法。这是一个很好的方法,但不能取代规范化状态。(将这两种方法结合起来是个好主意。)这个解决方案在我看来并不像它应该做的那样。当第二个请求传入时,您希望中止第一个请求。然而,存储中的承诺似乎起到了保护作用,它可以防止在运行中发出任何其他请求:“您的异步操作创建者应该做的第一件事是检查存储中是否存在承诺,如果存在,则将其中止。”@Richardinho By“如果存在,则将其中止”,我的意思是中止现有的请求,不要中止正在制作的新的。这更有意义吗?是的,听起来你是说如果有一个现有的请求,那么你就放弃,不做任何其他事情。我有一个不同的情况。如果我也有
currentPostId
postById
,但我必须同时获取所有帖子的数据(创建时,预览图片、元数据等),我该怎么办然后只获取一篇选定帖子的内容,并将该内容与该帖子的所有其他内容一起缓存在
postById
?@DanAbramov Hi我知道这是一个非常老的问题,但由于任何动作创建者都无法访问该状态,action creator如何决定是缓存了它还是需要获取远程对象?如果您有
currentListOfSearchResults
这是一个数组,而不是一个
currentPost
,该怎么办?我通常会跳过这些结果的Redux,而只是将它们放在页面组件的本地状态。我很欣赏这种解决方案。但是,我找不到一个很好的解释来说明在下面的场景中应该做什么:1。您有可以动态创建的父级。2.每个父级都有5个子级,它们都发出获取请求。这些孩子都有自己的减压器来促进这一点。3.如果我在应用程序中创建一个新的父级,我需要创建新的子级缩减器,或者取消以前活动父级的所有飞行中请求,并为当前活动父级启动新请求。有人遇到过类似的情况吗?我已经阅读并尝试了丹关于代码拆分的回复,但没有效果。@Dan Abra