A React component is a function that accepts an object of inputs (props) and returns JSX describing what to render. Props are React’s mechanism for passing data from parent to child — they are the primary way components communicate. Understanding how to design component interfaces through props — what to expose, what to default, what to make required — is fundamental to building a reusable component library for the blog application.
Function Components and Props
// ── Basic component with props ─────────────────────────────────────────────────
function Greeting({ name, role }) {
return (
<p>Hello, {name}! You are logged in as {role}.</p>
);
}
// Usage:
<Greeting name="Alice" role="editor" />
// ── Destructuring props in the parameter (recommended) ────────────────────────
function PostCard({ title, body, author, publishedAt, viewCount = 0 }) {
// ↑ default value
return (
<article>
<h2>{title}</h2>
<p>{body}</p>
<footer>
{author.name} · {new Date(publishedAt).toLocaleDateString()} · {viewCount} views
</footer>
</article>
);
}
// ── Using the whole props object (less common) ─────────────────────────────────
function PostCard(props) {
const { title, body } = props; // destructure inside the function
return <article>...</article>;
}
Note: Props are read-only — a component must never modify its own props. This is one of React’s fundamental rules: data flows down (from parent to child via props), events flow up (from child to parent via callback props). If a child needs to update data, the parent passes a callback function as a prop (
onLike={handleLike}), the child calls it, and the parent updates its state, causing a re-render that flows new props back down to the child.
Tip: The special
children prop receives anything placed between a component’s opening and closing tags. <Card><h1>Title</h1></Card> gives the Card component a children prop equal to <h1>Title</h1>. Use children for layout and wrapper components (Card, Modal, Section) that need to render arbitrary content inside a styled container.Warning: Component names must start with a capital letter —
PostCard, not postCard. React uses the capitalisation to distinguish between HTML elements (<div>, <p>) and React components (<PostCard>). A lowercase component name is treated as an HTML element, which means <postCard /> would attempt to create a non-standard <postcard> DOM element rather than calling your component function.Reusable Blog Components
// src/components/Avatar.jsx
function Avatar({ src, name, size = 40 }) {
return (
<img
src={src || "/default-avatar.png"}
alt={`${name}'s avatar`}
width={size}
height={size}
className="rounded-full object-cover"
style={{ width: size, height: size }}
/>
);
}
// src/components/Badge.jsx
function Badge({ children, variant = "default" }) {
const colours = {
default: "bg-gray-100 text-gray-700",
success: "bg-green-100 text-green-700",
warning: "bg-yellow-100 text-yellow-700",
published: "bg-blue-100 text-blue-700",
draft: "bg-gray-100 text-gray-500",
};
return (
<span className={`px-2 py-1 rounded text-xs font-medium ${colours[variant] || colours.default}`}>
{children}
</span>
);
}
// src/components/Button.jsx
function Button({ children, onClick, variant = "primary", disabled = false, type = "button" }) {
const styles = {
primary: "bg-blue-600 text-white hover:bg-blue-700",
secondary: "bg-gray-100 text-gray-700 hover:bg-gray-200",
danger: "bg-red-600 text-white hover:bg-red-700",
ghost: "bg-transparent text-blue-600 hover:bg-blue-50",
};
return (
<button
type={type}
onClick={onClick}
disabled={disabled}
className={`px-4 py-2 rounded font-medium transition-colors
${styles[variant]}
${disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}`}
>
{children}
</button>
);
}
// Usage:
<Avatar src={user.avatar_url} name={user.name} size={48} />
<Badge variant="published">Published</Badge>
<Button variant="primary" onClick={handleSubmit}>Save Post</Button>
<Button variant="danger" disabled={isDeleting}>
{isDeleting ? "Deleting..." : "Delete"}
</Button>
Children Prop for Layout Components
// Layout component using children
function Card({ title, children, className = "" }) {
return (
<div className={`bg-white rounded-lg shadow p-6 ${className}`}>
{title && <h3 className="text-lg font-semibold mb-4">{title}</h3>}
{children}
</div>
);
}
// Usage — children is everything between the tags:
<Card title="Recent Posts">
<PostList posts={posts} />
<Pagination page={page} total={total} />
</Card>
Common Mistakes
Mistake 1 — Lowercase component name
❌ Wrong — treated as HTML element, not component:
function postCard(props) { return <article>...</article>; }
<postCard title="Hello" /> // creates <postcard> DOM element, not a React component!
✅ Correct — always start with a capital letter:
function PostCard(props) { ... }
<PostCard title="Hello" /> // ✓ calls the PostCard function
Mistake 2 — Modifying props directly
❌ Wrong — props are read-only:
function PostCard({ post }) {
post.title = post.title.toUpperCase(); // NEVER mutate props!
return <h2>{post.title}</h2>;
}
✅ Correct — compute derived values without mutation:
function PostCard({ post }) {
const upperTitle = post.title.toUpperCase(); // ✓ new variable
return <h2>{upperTitle}</h2>;
}
Quick Reference
| Pattern | Code |
|---|---|
| Function component | function Name({ prop1, prop2 }) { return <JSX />; } |
| Default prop value | function Name({ size = 40 }) |
| Children prop | function Card({ children }) { return <div>{children}</div>; } |
| Pass callback | <Button onClick={() => handleClick(id)} /> |
| Spread props | <input {...inputProps} /> |