我认为这更像是一个概念/架构问题,但我会包括代码示例来帮助解释这个问题。我有一个规范化的 redux 状态,其中实体状态切片如下所示:
entities: {
projects: {
[id]: {...},
[id]: {...},
...
},
assignments: {
[id]: {...},
[id]: {...},
...
}
}
单个作业如下所示:
{
id: 1,
name: 'assignment 1',
status: 'active',
deadline: '01-01-2020'
}
我从后端数据库获取此数据。我正在尝试找出处理更新此数据的过程的正确方法,保持 UI 响应并保持我的 redux 状态与后端同步。
一个具体的例子是一个 react 组件,用于显示单个分配,该分配具有用于更改以下状态的选取器/单选按钮:
const statusOptions = {
'active',
'pending',
'complete'
}
我可以看到的选项是:
1( 将选取器的值设置为props.assignment.status
值,并在选取器/选择器的 onChange 中调度一个updateAssignment()
操作,其中 saga/thunk 发送 POST 请求并立即触发一个fetchAssignment()
操作,该操作将发送 GET 请求并更新 redux 状态,然后组件将重新呈现。
这样做的问题是 redux 更新需要太长时间,因此 UI 看起来滞后,受控输入将恢复到旧选择,直到传入新 props。
2( 根据 redux 状态设置本地组件状态,如下所示:
state = { status: this.props.assignment.status }
然后根据本地状态设置选取器的值,这将在值更改时提供近乎即时的 UI 更新。
我在这里看到的问题是我很确定这是一个反应反模式,我必须使用getDerivedStateFromProps()
或类似的东西来确保本地状态与 redux 状态保持同步。 另外,我真的很喜欢"单一事实来源"的想法,我觉得这个选项会使它无效。
3( 根据props.assignment.status
设置选取器的值,并在选取器的 onChange 处理程序中克隆assignment
对象,更新status
属性,然后立即发送将本地创建的assignment
对象合并到状态的updateAssignment()
操作。
之后,将 POST 请求发送到服务器,如果失败,以某种方式将 redux 状态恢复到以前的状态,基本上删除本地添加的assignment
对象。这似乎有点笨拙,虽然也许?
在更新 redux 数据的同时,是否有任何商定的最佳实践,同时保持单一事实来源、敏捷的 UI 和干净的代码?
(2(的第一部分在我看来是正确的方式。
在 ComponentDidMount 中(或者更好的是,在 App.js 中,当应用程序启动时(,您将数据从数据库提取到 redux 状态,并从中设置本地状态。
然后,在本地维护数据,并调度将更新 redux 状态和数据库的正确操作。
在 shouldComponentUpdate 中,您需要防止在此 redux 更新后发生的更新:您将检查 props 的值是否已更改。
在组件DidUpdate中,如果道具发生变化,您将更新状态。
最后要注意的是,如果可能发生这种情况,则在数据库更改后获取数据更新,这些更改是由其他智能手机上运行的应用程序的其他实例或其他数据源发生的。例如,在Firebase中,您可以通过聆听相关的应用更改来做到这一点。我不知道这是否与这里相关。