BeginnerReact Concepts

Props vs State in React — The Full Breakdown (With Real Thinking)

Props and state are both used for handling data in React, but they serve different purposes. This guide explains their differences, use cases, and how to choose between them for clean, reliable component logic.

By Rudraksh Laddha

In my first React job, I shipped a bug that crashed our entire user dashboard. The culprit? I was treating props like state and accidentally mutating them directly. That painful lesson taught me something no tutorial ever did: understanding props vs state isn't just theory—it's the difference between maintainable code and production disasters.

The question every React developer faces: "Should this be props or state?"

If you've been wrestling with this decision, you're in good company. After building 40+ React applications and mentoring dozens of developers, I've learned that mastering this distinction is what separates junior developers from those who write production-ready code.

  • Why your component architecture matters more than you think
  • The mental model that changed how I approach component design
  • Real patterns I use to make these decisions in seconds

Let's break this down with the context you need to build React apps that scale.


The Mental Model That Changed Everything

Props: Your Component's API Contract

  • The interface between parent and child components
  • Think of them as function parameters for your component
  • Immutable by design—changing them breaks React's rendering model
  • They define what your component can do, not what it remembers

"Props are the arguments you pass to configure behavior. State is the memory that drives that behavior."

State: Your Component's Private Memory

  • Internal data that can change over time
  • Managed through useState() or useReducer()
  • Triggers re-renders when updated
  • Should be minimal and specific to avoid performance issues

"State answers: What does this component need to remember between renders?"


A Real-World Scenario

Picture this: You're building a user profile card for a social media app. The card needs to display user information (name, avatar, bio) and allow users to follow/unfollow.

The user data comes from props—it's passed down from a parent component that fetched it from an API. You can't and shouldn't modify this data directly.

The follow status lives in state—it's specific to this user's interaction with this profile and needs to update when they click the follow button.

This separation keeps your components predictable and your data flow clear.


Real React Code Example (Props vs State)

👇 Component with Internal State

import { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0); // component's private memory

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

Here, count is internal to the component. Each Counter maintains its own count value. When you click the button, only this component re-renders—that's the power of localized state.

👇 Component Configured via Props

const Welcome = ({ name, role, onUserClick }) => {
  return (
    <div onClick={() => onUserClick(name)}>
      <h1>Hello, {name}!</h1>
      <p>Role: {role}</p>
    </div>
  );
};

const App = () => {
  const handleUserClick = (userName) => {
    console.log(`${userName} was clicked`);
  };

  return (
    <Welcome 
      name="Sarah" 
      role="Developer" 
      onUserClick={handleUserClick} 
    />
  );
};

The Welcome component is completely configured by its props. It's reusable—pass different props, get different behavior. Notice how we also pass functions as props to handle events.


⚔️ Detailed Comparison Table — Props vs State

Feature Props State
Source Passed from parent Defined and managed inside component
Editable? ❌ Read-only ✅ Can change using setState
Purpose Configure component behavior Track component's internal state
Triggers re-render? ✅ Yes, if value changes ✅ Yes, always on change
Used by All React components Components needing internal memory
Lifecycle role Configuration input Dynamic memory
Who updates it? Parent component The component itself

My Decision Framework for Props

After years of React development, I use this mental checklist:

  • Does this data come from outside the component? → Props
  • Do I want this component to be reusable? → Props for configuration
  • Should the parent control this behavior? → Props
  • Is this data the same for the component's entire lifecycle? → Props

Props create predictable, testable components. When I can configure a component entirely through props, I know it's going to be easy to debug and maintain.


My Decision Framework for State

State is for when props aren't enough:

  • Does this change based on user interaction? → State
  • Do I need to track: form inputs, loading status, modal visibility, search filters? → State
  • Does this component need to "remember" something between renders? → State
  • Is this specific to this component instance? → State

I keep state as minimal as possible. Each piece of state is a potential source of bugs, so I only add it when I truly need dynamic behavior.


Production Pattern: Combining Props and State

Here's a pattern I use constantly—a component that's configurable via props but manages its own interaction state:

const LikeButton = ({ 
  postId, 
  initialLiked = false, 
  onLike, 
  disabled = false 
}) => {
  const [liked, setLiked] = useState(initialLiked);
  const [loading, setLoading] = useState(false);

  const handleLike = async () => {
    if (disabled || loading) return;
    
    setLoading(true);
    try {
      await onLike(postId, !liked);
      setLiked(!liked);
    } catch (error) {
      // Handle error - maybe show a toast
      console.error('Failed to like post:', error);
    } finally {
      setLoading(false);
    }
  };

  return (
    <button 
      onClick={handleLike}
      disabled={disabled || loading}
      className={`btn ${liked ? 'liked' : 'not-liked'}`}
    >
      {loading ? '...' : liked ? "❤️" : "🤍"} Like
    </button>
  );
};

Usage in a parent component:

const PostCard = ({ post }) => {
  const handleLike = async (postId, isLiked) => {
    // API call to like/unlike post
    await api.updateLike(postId, isLiked);
  };

  return (
    <div className="post-card">
      <h3>{post.title}</h3>
      <p>{post.content}</p>
      <LikeButton 
        postId={post.id}
        initialLiked={post.isLiked}
        onLike={handleLike}
      />
    </div>
  );
};

This pattern gives you the best of both worlds: reusable component logic with customizable behavior. The parent controls what happens when you like a post, but the button manages its own visual state and loading behavior.


Hard-Learned Lessons About Props and State

  • Never mutate props directly — I've seen this break React's reconciliation and cause silent bugs
  • Minimize state surface area — fewer state variables mean fewer ways things can go wrong
  • Use multiple useState calls rather than one giant state object
  • Lift state up sparingly — only when multiple components truly need shared access
  • Consider derived state — sometimes you don't need state at all, just computed values
  • ⚠️ Watch for stale closures — a common gotcha with state in event handlers

✅ Final Summary – Props vs State in React

Category Props State
What it is Component configuration API Component's private memory
Mutable? ❌ No ✅ Yes
Data flow Parent → Child Internal to component
React Hook Needed? ❌ No useState() or useReducer()
Primary purpose Reusability and configuration Dynamic behavior and memory
Performance impact Re-render when props change Re-render when state changes

Questions I Get About Props vs State in React

1. Can I update props inside a component?

No, and for good reason. Props are React's contract that data flows in one direction. Mutating props breaks this contract and can cause unpredictable re-render behavior. Always update props from the parent component.

2. Can I pass state as a prop to a child?

Absolutely—this is a fundamental React pattern. You often pass both state values and state setters as props to create controlled components. This keeps your data flow predictable while allowing child components to trigger updates.

3. When should I "lift state up"?

When multiple sibling components need access to the same data. Move the state to their closest common parent and pass it down as props. But don't over-do it—lifting state too high creates unnecessary re-renders and prop drilling.

4. Can a component have both props and state?

Yes, and most production components do. Props configure how the component behaves, state tracks how it's currently behaving. This separation keeps your components both reusable and interactive.

5. What about derived state vs props?

If you can compute a value from existing props or state, don't store it in state. Use useMemo for expensive calculations. Derived state is often a sign that you can simplify your component logic.

❤️ At Learn Virendana, we love creating high-quality React tutorials that simplify complex concepts and deliver a practical, real-world React learning experience for developers