【发布时间】:2023-03-18 13:15:02
【问题描述】:
假设我们的学校有一些数据,包括姓名和学生名单,学生有一些数据,包括他们注册的课程和对他们学校的引用。在客户端:
- 我想显示一个显示学校信息的屏幕,其中包括按姓名列出的所有学生的列表。
- 我想显示一个屏幕,其中显示有关学生的信息,包括他们学校的名称和他们正在学习的课程的名称。
- 我想缓存这些信息,这样我就可以显示相同的屏幕,而无需等待新的提取。我应该能够从一个学校到另一个学生再回到学校,而无需再次去学校。
- 我希望每个屏幕只显示一次提取。从学校页面转到学生页面可能需要单独获取,但我应该能够在一次获取中显示具有完整学生姓名列表的学校。
- 我想避免重复数据,这样如果学校名称发生变化,一次获取更新学校将导致正确的名称同时显示在学校页面和学生页面上。
有没有什么好的方法来做这一切,还是必须解除一些限制?
第一种方法是使用 API 来执行以下操作:
GET /school/1
{
id: 1,
name: "Jefferson High",
students: [
{
id: 1
name: "Joel Kim"
},
{
id: 2,
name: "Chris Green"
}
...
]
}
GET /student/1
{
id: 1,
name: "Joel Kim",
school: {
id: 1,
name: "Jefferson High"
}
courses: [
{
id: 3
name: "Algebra 1"
},
{
id: 5,
name: "World History"
}
...
]
}
这种方法的一个优点是,对于每个屏幕,我们只需进行一次提取。在客户端,我们可以规范化学校和学生,以便他们通过 ID 相互引用,然后将对象存储在不同的数据存储中。但是,嵌套在school 中的student 对象并不是一个完整的对象——它不包括嵌套的课程,或者对学校的引用。同样,student 内部的 school 对象没有所有在读学生的列表。在数据存储中存储对象的部分表示会导致客户端出现一堆复杂的逻辑。
我们可以存储学校和学生及其嵌套的部分对象,而不是规范化这些对象。然而,这意味着数据重复——杰斐逊高中的每个学生都会嵌套有学校的名称。如果在获取特定学生之前学校名称发生更改,那么我们会在其他地方显示该学生的正确学校名称,但在其他地方显示错误名称,包括在“学校详细信息”页面上。
另一种方法可能是将 API 设计为仅返回嵌套对象的 ID:
GET /school/1
{
id: 1,
name: "Jefferson High",
students: [1, 2]
}
GET /student/1
{
id: 1,
name: "Joel Kim",
school: 1,
courses: [3, 5]
}
我们总是拥有对象的“完整”表示及其所有引用,因此将这些信息存储在数据存储客户端非常容易。但是,这需要多次获取才能显示每个屏幕。要显示有关学生的信息,我们必须先获取该学生,然后再获取他们的学校和课程。
是否有更聪明的方法可以让我们只缓存每个对象的一个副本,并防止多次提取以显示基本屏幕?
【问题讨论】:
-
我喜欢这个问题,并发现讨论 here 在思考它时很有帮助。您的问题的标题提到了缓存,但正文没有。如果您使用第二种(标准化)方法,您的浏览器可以自己缓存请求,从而为您节省一些访问服务器的次数。
-
@this-vidor 感谢您的链接!我什至没有考虑浏览器缓存与仅在 Redux 状态的键值存储中保留对象(“缓存”)。我认为浏览器缓存和 Redux 状态如何一起使用将是一个实现细节,不一定会改变原始问题的答案。
-
不管怎样,我正在使用 Redux 和一个 Web 浏览器,但是相同的设计约束可以很容易地应用于使用其他一些客户端数据存储和一些其他客户端数据存储的任何其他客户端(例如本机应用程序)其他带有缓存的 HTTP 客户端。
标签: rest reactjs data-structures redux api-design