State Normalization
State normalization stores shared entities once, keyed by stable identifiers, instead of duplicating the same entity inside multiple nested structures. This reduces inconsistent updates and makes shared data easier to update, select, and cache.
A normalized state shape separates entities into collections such as `users`, `posts`, or `products`, where each record is stored under an ID. Other state structures keep only the IDs needed to reference those records.
For example, instead of storing the same user object inside every post, state can contain `usersById[userId]` and let each post store `authorId`. Updating that user's name then requires changing one record rather than finding every embedded copy.
Normalization is especially useful when entities are shared by multiple parts of the UI, have relationships with other entities, or are updated independently. It also makes selectors more predictable because they can retrieve an entity by ID and compose the data needed by a component.
The trade-off is that reads may require joining related records. A frontend architecture therefore needs selectors or helper functions that reconstruct useful views from the normalized entities.
Key points
- Store each shared entity once under a stable ID.
- Use IDs to represent relationships between entities.
- Centralize updates to avoid divergent copies of the same data.
- Use selectors or derived functions to rebuild nested views when needed.
- Normalization is most valuable for shared, relational, frequently updated data.
Interview questions
What is state normalization, and why would you use it in a frontend application?
State normalization means storing each shared entity in one canonical collection keyed by an identifier. Related data stores references such as IDs instead of repeated object copies. This reduces duplication and makes updates consistent. The UI can use selectors to reconstruct the nested view it needs.
How does normalization prevent inconsistent updates?
If the same entity appears in several nested locations, changing one copy can leave the others stale. With normalized state, all references point to the same entity record by ID. An update therefore changes the canonical record once. Consumers that resolve that ID see the updated entity without requiring multiple copies to be synchronized.
What are the trade-offs of normalized state?
Normalization reduces duplication and simplifies shared updates, but it can make reads more indirect. A component may need to resolve several IDs and combine records to create the shape it needs. That composition can be handled with selectors or memoized derived data. For small, isolated state, the additional structure may not provide enough benefit to justify the complexity.
How would you normalize a list of posts that contains embedded authors and comments?
I would separate each entity type into an ID-keyed collection, such as `postsById`, `usersById`, and `commentsById`. Posts would reference authors with `authorId`, while comments could reference both their `postId` and `authorId`. Lists or ordering information can be represented separately with arrays of IDs when needed. Selectors can then compose a post with its author and comments for presentation.