DEV Community

Abdullah Ahmed
Abdullah Ahmed

Posted on

Data Normalization in Frontend Development: Simplifying Complex State Introduction

When working on modern frontend applications, especially those with dynamic and interconnected data (like posts, comments, and users), managing state can quickly become complicated. APIs often return deeply nested data, and performing updates, deletions, or additions on such structures can feel like navigating a maze.

For instance, imagine an app like Facebook or Reddit. Each post has comments, each comment has users, and each user might appear in multiple comments or posts. If you try to edit or delete a user, you’d have to find and update that user’s data in every place they appear. This approach quickly becomes unmanageable.

That’s where data normalization comes in.

What Is Data Normalization?

Normalization means organizing your data so that each piece of information exists in exactly one place.
Instead of keeping a deeply nested structure, you store data in flat, relational objects, similar to how relational databases work.

For example:

Instead of keeping users nested inside comments, which are nested inside posts,

You separate them into different collections (posts, comments, users),

Then you use IDs to link them together.

This makes it much easier to update, delete, or add new data consistently.

The Problem: Nested Data Example

Let’s say our API returns this data for posts:

const posts = [
  {
    id: 1,
    title: "Understanding React",
    comments: [
      {
        id: 101,
        text: "Great post!",
        user: {
          id: 1001,
          name: "Abdallah Ahmed",
        },
      },
      {
        id: 102,
        text: "Thanks for sharing",
        user: {
          id: 1002,
          name: "Sara Ali",
        },
      },
    ],
  },
];
Enter fullscreen mode Exit fullscreen mode

Now, imagine you need to update the user’s name (for example, Abdallah changes his name).
You’ll have to:

Loop through each post,

Then through each comment,

Then find the user,

And finally update the name.

That’s a lot of unnecessary traversal — and if the same user appears in multiple posts or comments, you’ll need to update every occurrence manually.
This leads to data duplication and inconsistent states.

The Solution: Normalized Data Structure

After normalization, we can represent the same data like this:

const normalizedData = {
  posts: {
    1: { id: 1, title: "Understanding React", comments: [101, 102] },
  },
  comments: {
    101: { id: 101, text: "Great post!", user: 1001 },
    102: { id: 102, text: "Thanks for sharing", user: 1002 },
  },
  users: {
    1001: { id: 1001, name: "Abdallah Ahmed" },
    1002: { id: 1002, name: "Sara Ali" },
  },
};
Enter fullscreen mode Exit fullscreen mode

Now, all entities (posts, comments, users) are stored separately and referenced by IDs.

Example Operations

  1. Updating a User’s Name

Before normalization:

// Update user's name (nested approach)
posts.forEach(post => {
  post.comments.forEach(comment => {
    if (comment.user.id === 1001) {
      comment.user.name = "Abdallah A.";
    }
  });
});
Enter fullscreen mode Exit fullscreen mode

After normalization:

// Simple and efficient
normalizedData.users[1001].name = "Abdallah A.";
Enter fullscreen mode Exit fullscreen mode

Only one update is needed — and all parts of your app that reference this user will automatically get the updated name.

  1. Deleting a Comment

Before normalization:

// Remove comment 101
posts[0].comments = posts[0].comments.filter(c => c.id !== 101);
Enter fullscreen mode Exit fullscreen mode

After normalization:

// Delete from comment list
delete normalizedData.comments[101];

// Remove reference from the post

normalizedData.posts[1].comments = normalizedData.posts[1].comments.filter(
  id => id !== 101
);

Enter fullscreen mode Exit fullscreen mode

Clean, simple, and consistent — no deeply nested loops.

  1. Adding a New Comment

Before normalization:


const newComment = {
  id: 103,
  text: "Very helpful!",
  user: { id: 1003, name: "Ali Mohamed" },
};

posts[0].comments.push(newComment);
Enter fullscreen mode Exit fullscreen mode

After normalization:

normalizedData.users[1003] = { id: 1003, name: "Ali Mohamed" };
normalizedData.comments[103] = { id: 103, text: "Very helpful!", user: 1003 };
normalizedData.posts[1].comments.push(103);
Enter fullscreen mode Exit fullscreen mode

The data remains structured, and each entity is tracked in one place.

Benefits of Normalization

✅ Easier updates – Change data in one place, not everywhere.
✅ Less duplication – Each entity exists only once.
✅ Simplified logic – Easier to add, remove, or merge entities.
✅ Improved performance – Less re-rendering and simpler lookups in UI frameworks like React.
✅ Scalable structure – Works great as your app and data grow in complexity.

Top comments (0)