React Beginner

Props in React - Passing Data Between Components

CodingerWeb
CodingerWeb
21 views 55 min read

What are Props?

Props (short for "properties") are a way to pass data from parent components to child components in React. They make components reusable and dynamic by allowing them to receive different data and behave accordingly.

Understanding Props

Think of props like function parameters - they allow you to customize how a component behaves:

// Parent component passing props
function App() {
  return (
    <div>
      <Greeting name="Alice" age={25} />
      <Greeting name="Bob" age={30} />
    </div>
  );
}

// Child component receiving props
function Greeting(props) {
  return (
    <div>
      <h2>Hello, {props.name}!</h2>
      <p>You are {props.age} years old.</p>
    </div>
  );
}

Destructuring Props

You can destructure props to make your code cleaner:

// Method 1: Destructuring in function parameter
function Greeting({ name, age }) {
  return (
    <div>
      <h2>Hello, {name}!</h2>
      <p>You are {age} years old.</p>
    </div>
  );
}

// Method 2: Destructuring inside function
function Greeting(props) {
  const { name, age } = props;
  
  return (
    <div>
      <h2>Hello, {name}!</h2>
      <p>You are {age} years old.</p>
    </div>
  );
}

Types of Props

Props can be any JavaScript data type:

function UserProfile({ 
  name,           // string
  age,            // number
  isActive,       // boolean
  hobbies,        // array
  address,        // object
  onButtonClick   // function
}) {
  return (
    <div className="user-profile">
      <h2>{name}</h2>
      <p>Age: {age}</p>
      <p>Status: {isActive ? "Active" : "Inactive"}</p>
      
      <div>
        <h3>Address:</h3>
        <p>{address.street}, {address.city}</p>
      </div>
      
      <div>
        <h3>Hobbies:</h3>
        <ul>
          {hobbies.map((hobby, index) => (
            <li key={index}>{hobby}</li>
          ))}
        </ul>
      </div>
      
      <button onClick={onButtonClick}>
        Contact User
      </button>
    </div>
  );
}

// Using the component
function App() {
  const user = {
    name: "Sarah Johnson",
    age: 28,
    isActive: true,
    hobbies: ["Reading", "Photography", "Hiking"],
    address: {
      street: "123 Main St",
      city: "New York"
    }
  };
  
  const handleContactClick = () => {
    alert(`Contacting ${user.name}...`);
  };
  
  return (
    <UserProfile
      name={user.name}
      age={user.age}
      isActive={user.isActive}
      hobbies={user.hobbies}
      address={user.address}
      onButtonClick={handleContactClick}
    />
  );
}

Default Props

You can set default values for props:

function Button({ text, color, size, onClick }) {
  return (
    <button 
      className={`btn btn-${color} btn-${size}`}
      onClick={onClick}
    >
      {text}
    </button>
  );
}

// Method 1: Default parameters
function Button({ 
  text = "Click me", 
  color = "primary", 
  size = "medium", 
  onClick = () => {} 
}) {
  return (
    <button 
      className={`btn btn-${color} btn-${size}`}
      onClick={onClick}
    >
      {text}
    </button>
  );
}

// Method 2: defaultProps (legacy)
Button.defaultProps = {
  text: "Click me",
  color: "primary",
  size: "medium",
  onClick: () => {}
};

Props Validation with PropTypes

You can validate props to catch errors early:

import PropTypes from 'prop-types';

function UserCard({ name, age, email, isAdmin }) {
  return (
    <div className="user-card">
      <h3>{name}</h3>
      <p>Age: {age}</p>
      <p>Email: {email}</p>
      {isAdmin && <span className="admin-badge">Admin</span>}
    </div>
  );
}

UserCard.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired,
  email: PropTypes.string.isRequired,
  isAdmin: PropTypes.bool
};

UserCard.defaultProps = {
  isAdmin: false
};

Children Prop

The special `children` prop allows you to pass content between component tags:

function Card({ title, children }) {
  return (
    <div className="card">
      <div className="card-header">
        <h3>{title}</h3>
      </div>
      <div className="card-body">
        {children}
      </div>
    </div>
  );
}

// Using the Card component
function App() {
  return (
    <div>
      <Card title="User Information">
        <p>This content is passed as children</p>
        <button>Edit Profile</button>
      </Card>
      
      <Card title="Statistics">
        <ul>
          <li>Total Users: 1,234</li>
          <li>Active Sessions: 89</li>
        </ul>
      </Card>
    </div>
  );
}

Conditional Props

You can conditionally pass props:

function ProductCard({ product, showDiscount }) {
  return (
    <div className="product-card">
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      
      {showDiscount && product.discount && (
        <div className="discount">
          {product.discount}% OFF!
        </div>
      )}
      
      <button>Add to Cart</button>
    </div>
  );
}

function App() {
  const products = [
    { id: 1, name: "Laptop", price: 999, discount: 10 },
    { id: 2, name: "Phone", price: 699, discount: null }
  ];
  
  return (
    <div>
      {products.map(product => (
        <ProductCard 
          key={product.id}
          product={product}
          showDiscount={true}
        />
      ))}
    </div>
  );
}

Practical Exercise: Building a Blog Post Component

function BlogPost({ 
  title, 
  author, 
  date, 
  content, 
  tags, 
  readTime,
  onLike,
  onShare 
}) {
  return (
    <article className="blog-post">
      <header>
        <h1>{title}</h1>
        <div className="post-meta">
          <span>By {author}</span>
          <span>{date}</span>
          <span>{readTime} min read</span>
        </div>
      </header>
      
      <div className="post-content">
        {content}
      </div>
      
      <div className="post-tags">
        {tags.map((tag, index) => (
          <span key={index} className="tag">
            #{tag}
          </span>
        ))}
      </div>
      
      <footer className="post-actions">
        <button onClick={onLike}>❤️ Like</button>
        <button onClick={onShare}>📤 Share</button>
      </footer>
    </article>
  );
}

// Using the BlogPost component
function App() {
  const post = {
    title: "Getting Started with React Props",
    author: "Jane Developer",
    date: "March 15, 2024",
    content: "Props are one of the most important concepts in React...",
    tags: ["React", "JavaScript", "Frontend"],
    readTime: 5
  };
  
  const handleLike = () => {
    console.log("Post liked!");
  };
  
  const handleShare = () => {
    console.log("Post shared!");
  };
  
  return (
    <div className="app">
      <BlogPost
        title={post.title}
        author={post.author}
        date={post.date}
        content={post.content}
        tags={post.tags}
        readTime={post.readTime}
        onLike={handleLike}
        onShare={handleShare}
      />
    </div>
  );
}

Best Practices for Props

  • Keep props simple: Pass only the data that the component needs
  • Use descriptive names: Make prop names clear and meaningful
  • Validate props: Use PropTypes or TypeScript for type checking
  • Avoid prop drilling: Don't pass props through many levels unnecessarily
  • Use default props: Provide sensible defaults for optional props
  • Destructure props: Makes code more readable and easier to maintain

Common Mistakes to Avoid

  • Mutating props: Props are read-only, never modify them directly
  • Missing keys: Always provide keys when rendering lists
  • Passing too many props: Consider using objects or context for complex data
  • Not using PropTypes: Validation helps catch bugs early

Summary

Props are essential for creating reusable and dynamic React components. You've learned how to pass different types of data, use default props, validate props, and work with the special children prop. In the next lesson, we'll explore state management and how components can manage their own internal data.