gpt4 book ai didi

javascript - 如何跟踪 Redux 中不同 API 调用的状态?

转载 作者:行者123 更新时间:2023-12-01 02:34:13 24 4
gpt4 key购买 nike

假设我有一个用于管理待办事项的应用程序,用户可以通过单击按钮添加新的待办事项。
当用户单击该按钮时,将出现一个微调器,直到待办事项保存到后端或请求失败。

当按下按钮时,会调度一个名为 ADD_TODO_REQUEST 的操作,然后该操作将被 redux-observable 史诗拦截,该史诗将执行 HTTP 请求来保存待办事项,并调度一个 ADD_TODO_COMPLETE 操作或 ADD_TODO_FAILED 操作,具体取决于 HTTP 请求结果。

应用程序应在“添加待办事项”按钮旁边显示一个微调器。
为此,我的状态包含一个名为 isSaving 的标志,当 HTTP 请求挂起时,该标志将设置为 true;当 HTTP 请求完成时,该标志将重置为 false。

我的初始状态形状如下所示:

{
todos: [],
isSaving: false
}

当应用程序启动时,将分派(dispatch)的第一个操作是 FETCH_TODO_REQUEST ,它将调用另一个 API 端点来获取所有待办事项。

应用程序应再次显示一个旋转图标,通知用户正在下载待办事项,为此,我向名为 isFetching 的状态添加了另一个标志。
需要这个新标志,因为如果我在添加待办事项时共享相同的标志,那么当用户只是添加待办事项时,我会为整个应用程序显示一个微调器。

我的初始状态形状现在看起来像这样:

{
todos: [],
isSaving: false,
isFetching: false
}

这种方法对我来说看起来不错,但如果用户也可以删除待办事项,我必须跟踪这个额外的 HTTP 请求状态,因此我需要添加另一个标志(可能称为 isDeleting )到国家。

请注意,我想在“添加按钮”旁边显示一个微调器,并在每个要删除的待办事项旁边显示一个微调器。这些旋转器可以同时出现,这就是为什么一个标志是不够的,我已经采用了这种方法。

在可能有许多不同的并发 API“操作”的情况下,我需要为每个可能的请求设置一个标志。
如果我还想显示错误,那么现在每个可用的 API“操作”都需要两个属性:一个用于表示请求正在进行,另一个用于保存错误对象。

这种方法的问题在于它看起来非常非常、冗长。

是否有一种惯用且更智能的方法来跟踪并发 http 请求的状态?
为每个可能涉及同一“实体”的 http 请求设置一个标志是否正确?

最佳答案

我见过很多处理这个问题的方法,每种方法都有各自的优点和缺点。

每个资源都有自己的状态

虽然没有规则,但通常建议 redux 用户将其状态模式建模为数据库。

这主要意味着您将存储由某个 ID 索引的资源。在本例中,您有一个待办事项列表,因此您的状态可能如下所示:

{
todosById: {
'1': {
id: '1',
content: 'Do something'
},
'2': {
id: '2',
content: 'Do another thing'
}
}
}

当您想要一个包含所有待办事项的数组时,您可以在选择状态时即时创建它:

const selectTodos = (state) => Object.values(state.todosById);
/*
[{
id: '1',
content: 'Do something'
}, {
id: '2',
content: 'Do another thing'
}]
*/

const selectTodoIds = (state) => Object.keys(state.todosById)
// ['1', '2']

你为什么要这样做?原因之一是它使通过 ID 查找内容变得非常容易,这在用户流程中经常需要;例如显示事物列表,然后使用选择其中之一。

适用于您所描述的情况的另一个原因是我们现在可以单独跟踪每个资源的状态。因此,每个资源都可以有自己的 isFetchingisSaving 等。或者,如果您想保证资源仅处于单一状态,您可以使用枚举 -但请注意,确实不可能同时获取和保存!

{
todosById: {
'1': {
id: '1',
content: 'Do something',
isFetching: false,
isSaving: false
},
'2': {
id: '2',
content: 'Do another thing',
isFetching: false,
isSaving: false
}
}
}

interface Todo {
id: string;
content: string;
isFetching: boolean;
isSaving: boolean;

// or using an enum. here are some possibilities:
enum Status { Fetching, Saving, New, Prestine, Dirty }
status: Status;
}

当您的用户直接访问其中一项资源时,这也很自然地起作用。例如如果他们可以导航到单个 Todo,您可以将其填充到 todosById 中并以同样的方式跟踪其状态。如果您稍后还加载待办事项列表,则来自服务器的最新值将合并到我们之前加载的待办事项中。

在客户端创建新资源时,在将其保存到服务器之前,您可能还没有它的 ID。在这种特殊情况下,我有一个仅在客户端生成和使用的临时 ID。例如'tmp-todo-1''tmp-todo-2'

{
todosById: {
'tmp-todo-1': {
id: 'tmp-todo-1',
content: 'A new todo that has never been saved yet',
status: Status.New
},
'1': {
id: '1',
content: 'A todo that has been created but has unsaved changes',
status: Status.Dirty
},
'2': {
id: '2',
content: 'Do another thing',
status: Status.Prestine
}
}
}

独立状态

更复杂的资源请求管理的另一个选择是使其完全独立,并且与它的获取/保存等资源无关。

与此类似的东西:

{
meta: {
'1': {
isFetching: false,
isSaving: false
},
'2': {
isFetching: false,
isSaving: false
}
},
todosById: {
'1': {
id: '1',
content: 'Do something'
},
'2': {
id: '2',
content: 'Do another thing'
}
}
}

这样做的好处是不需要将资源本身与服务器上未包含的仅客户端状态合并,例如 isFetching

这有很多变体,人们已经围绕其中一些创建了库,例如 redux-resource ,尽管我没有使用过那个特定的库,所以我不能多说。我使用自己制作的自定义抽象。

关于javascript - 如何跟踪 Redux 中不同 API 调用的状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48050993/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com