如何避免让不再有用​​的异步 thunk(应用程序不再期望它)能够更新状态?

How to avoid letting an async thunk that is no longer useful (the app is not expecting it anymore) from being able to update the state?

我的单页应用程序 (React + Redux) 上有以下模式。

每次在应用程序上加载页面时它都会运行。用户导航到特定页面,并调度 loadPageThunk。页面的初始状态向用户显示一个微调器。这用于例如博客文章页面。

thunk 将获取一些异步数据(博文),然后显示包含该数据的页面。

它工作正常。当用户离开页面时。 useEffect 调度 RESET 操作以将状态重置回其初始值。

我的问题是:

如果异步调用完成时间太长并且用户导航离开怎么办?它会产生一个问题,因为现在有一个未决的承诺将在意外的时间完成。我怎样才能阻止完成更新我的状态?

想象一下需要 10 秒才能完成的异步调用的以下步骤:

#### FIRST PAGE LOAD ####

USER VISITS blog/slug-1
loadPageThunk() IS DISPATCHED
blogPost1 STARTS GETTING FETCHED (WILL TAKE 10 SECONDS)
USER NAVIGATES AWAY

#### SECOND PAGE LOAD ####

USER VISITS blog/slug-2
blogPost2 STARTS GETTING FETCHED (WILL TAKE 10 SECONDS)
USER IS STILL SEEING SPINNER
blogPost1 (FROM THE PREVIOUS VISIT) HAS COMPLETE AND WILL UPDATE THE STATE
USER NOW SEES blog/slug-2 WITH THE DATA FROM blogPost1 WHICH IS AN ERROR
blogPost2 WILL EVENTUALLY COMPLETE AND USER WILL SEE A CONTENT FLICKER ON THE PAGE

问题

如何避免不再有用的未决承诺无法更新状态?

我的应用目前没有出现这个问题,但我认为好的设计应该可以解决这个问题。

我是否应该为我的 LOAD_PAGE 循环添加一个 ID,这样我可以在允许 callbacks / async code 在 ID 不匹配时更新状态之前检查当前循环的 ID ?人们通常如何处理这种情况?

createAsyncThunk 返回的承诺附加了一个 abort() 方法,可用于 'cancel' 承诺。参见 canceling while running。您可以在清理中调用 abort() 以防止 thunk 成为 fulfilled.

在你的减速器中,如果你正在为你的 thunk 处理 rejected 情况,那么你可以为错误名称为 AbortError 的情况添加一个例外,而不是什么也不做。

扩展一下你的具体情况:一个好的经验法则是,如果你发现自己在卸载组件时处于 'resetting' 状态,那么它应该首先是本地组件状态.

我个人将博客数据存储为 entities(posts、评论等),由 id 和 collections 键控。该集合只是特定页面上 post 个 ID 的数组。

例如,

{
  entities: {
     posts: {
       1: {...},
       2: {...}
     },
     comments: {
        123: {...},
        999: {...}
     }
  },
  collections: {
     "blog/slug-1": [99,98,97...],
     "blog/slug-2": [89,88,87...],
  }
}

这种结构意味着每个页面都可以在正确的地方保存它的数据,不管它是不是当前页面。这也意味着每个页面都可以 select 自己的数据,并且可以查看该数据是否已存在于状态中。