规范化 (Normalization) 是指将数据存储在平面、关系型结构中 — 在查找表中通过 id 作为键 — 而不是深度嵌套的对象/数组。这与数据库规范化的思想相同,但应用于客户端状态,使更新和查找高效且一致。
嵌套/反规范化状态的问题
js
: [
{ : , : , : { : , : } },
{ : , : , : { : , : } },
]
重复的嵌套数据必须在许多地方更新(存在不一致的风险),查找项目意味着扫描数组(O(n))。
// ✅ flat lookup tables keyed by id, with references by id
{
posts: {
byId: { 1: { id: 1, title: "A", authorId: 10 }, // reference the author by id
2: { id: 2, title: "B", authorId: 10 } },
allIds: [1, 2], // order/iteration
},
users: {
byId: { 10: { id: 10, name: "Ann" } }, // each user stored ONCE
},
}
每个实体存储一次,通过 id 作为键;关系只是 id 引用。
state.users.byId[10]; // ✅ O(1) lookup by id
state.users.byId[10] = { ...u, name: "Bob" }; // ✅ update Ann ONCE → reflected everywhere
state.posts.allIds.map(id => state.posts.byId[id]); // iterate via the id list
✓ Single source of truth per entity → no duplication, no drift
✓ O(1) lookups/updates by id (vs scanning arrays)
✓ Easy to update one entity and have all references reflect it
✓ Simpler to manage relationships and merge new data
Redux Toolkit's createEntityAdapter generates normalized { ids, entities }
structures + CRUD reducers automatically. normalizr can normalize API responses.
规范化是在客户端状态中管理 关系/集合数据 的标准模式(尤其是在 Redux 中)。
它为每个实体强制实施单一数据源(更新一次,处处生效),提供快速的基于 id 的查找,并避免深度嵌套、重复数据带来的 bug 和性能问题。
对于包含相关实体(用户、帖子、评论)的应用,这些实体会被更新和交叉引用,规范化存储 — 通常通过 createEntityAdapter — 是保持状态一致和高效的关键技术。