如何避免让不再有用的异步 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 自己的数据,并且可以查看该数据是否已存在于状态中。
我的单页应用程序 (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 自己的数据,并且可以查看该数据是否已存在于状态中。