Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
ReactNext.jsJune 23, 20263 min read

React props vs state: Mastering Unidirectional Data Flow

Master React props vs state by visualizing unidirectional data flow. Learn where to store data to keep your components predictable and easy to debug.

ReactNext.jsFrontend ArchitectureState ManagementWeb DevelopmentTutorial

Last month, I spent three hours debugging a "ghost" update in a complex dashboard because a junior dev had synced a prop directly into a useState hook. It’s a classic mistake: treating props as local state, which creates a fractured source of truth that React can’t track properly.

If you’re struggling to decide where data belongs, you aren't alone. Understanding React props vs state is the single most important hurdle to clear if you want to stop fighting your own code.

The Mental Model: Unidirectional Data Flow

Think of your component tree as a waterfall. Data flows in one direction: from parent to child via props. This is the core of unidirectional data flow.

When you pass data down, the child component receives it as a read-only snapshot. If you try to modify that prop, React screams at you—or worse, it stays silent while your UI gets out of sync. Local state, by contrast, is internal. It’s the "private memory" of a component.

I often visualize it like this:

  • Props: "I was told this by my parent." (Read-only)
  • State: "I decided this myself." (Mutable)

If you ignore this distinction, you'll eventually run into bugs where your UI shows old data despite a state update. I highly recommend reviewing React state management and the unidirectional data flow to see why this architecture is non-negotiable for stability.

Why We Get It Wrong

Early in my career, I tried to "sync" props to state using useEffect. It looked something like this:

JAVASCRIPT
function UserProfile({ username }) {
  const [name, setName] = useState(username);

  useEffect(() => {
    setName(username);
  }, [username]);

  return <div>{name}</div>;
}

This is an anti-pattern. It forces the component to manage two sources of truth for the same piece of information. If username changes, the component has to re-render, run the effect, and then trigger another re-render to update the state. It’s inefficient and creates a lag of about 16ms to 32ms depending on the component complexity.

Instead, just use the prop directly. If you need to transform the data, derive it during render:

JAVASCRIPT
function UserProfile({ username }) {
  // Derived state is always in sync
  const displayName = username.toUpperCase();
  return <div>{displayName}</div>;
}

Component State Management Strategies

When you're building out your architecture, you need to decide if the data needs to be shared. If only one component cares about a value, keep it local. If three siblings need it, lift it up.

Learning how to structure this is covered in React props and state: Where your data should live. It’s easy to over-engineer by pulling everything into a global context, but simple is almost always better.

Before reaching for Redux or complex hooks, ask yourself:

  1. Does this data change? If no, it's a prop (or a constant).
  2. Is it passed from a parent? If yes, it's a prop.
  3. Does the component need to change it internally? If yes, it's state.

Practical Tips for Next.js State Patterns

In Next.js, this mental model becomes even more critical because of Server Components. You can't pass functions or complex class instances as props from Server to Client components.

If you’re working on a larger app, you’ll want to master React state management: Mapping Your Next.js Component Hierarchy to avoid prop drilling. I’ve found that by keeping my state as close to the leaf nodes as possible, I spend about 40% less time chasing down re-render issues during my on-call rotations.

What I Still Get Wrong

Honestly? I still over-complicate state sometimes. I’ll start building a complex useReducer for a form, only to realize halfway through that a simple useState would have sufficed.

The goal isn't to write the most "clever" state management code; it's to write code that's boring and predictable. If you find yourself writing complex logic to keep props and state in sync, stop. You’re fighting the framework, and the framework will eventually win.

Next time you're stuck, try deleting the state and seeing if you can compute the value from props instead. You’ll be surprised how often that solves the problem.

Back to Blog

Similar Posts

ReactNext.jsJune 23, 20264 min read

React Components: How to Choose the Right Boundaries

React components are often split too early or too late. Learn a practical mental model for component architecture that prioritizes performance and readability.

Read more
ReactNext.jsJune 23, 2026
5 min read

React state management: Distinguishing UI, Form, and Server State

React state management is often misunderstood. Learn to distinguish between UI state, form state, and server cache to build cleaner, more resilient apps.

Read more
ReactNext.jsJune 22, 20264 min read

React component architecture: Mastering Colocation for Better Maintainability

React component architecture thrives on colocation. Learn why grouping logic, state, and UI by feature beats file-type organization for scalable Next.js apps.

Read more