What are Components?
Components are the heart of React. Think of them as custom HTML elements that you can create,
customize, and reuse throughout your application. Just like you use <div>,
<button>, or <input> elements, you can create your own
components like <Header>, <UserProfile>, or <ProductCard>.
// HTML
<div id="user-cards"></div>
// JavaScript
function createUserCard(user) {
return `
<div class="user-card">
<img src="${user.avatar}" alt="${user.name}">
<h3>${user.name}</h3>
<p>${user.email}</p>
<button onclick="followUser(${user.id})">
Follow
</button>
</div>
`;
}
// Usage
document.getElementById('user-cards').innerHTML =
users.map(createUserCard).join('');
// UserCard Component
function UserCard({ user, onFollow }) {
return (
<div className="user-card">
<img src={user.avatar} alt={user.name} />
<h3>{user.name}</h3>
<p>{user.email}</p>
<button onClick={() => onFollow(user.id)}>
Follow
</button>
</div>
);
}
// Usage
<div>
{users.map(user =>
<UserCard
key={user.id}
user={user}
onFollow={followUser}
/>
)}
</div>
Understanding JSX
JSX (JavaScript XML) is React's syntax extension that lets you write HTML-like code in JavaScript. It might look strange at first, but it's just a more intuitive way to describe what your UI should look like.
๐ฏ JSX is NOT HTML
While JSX looks like HTML, it's actually JavaScript. Here are the key differences:
// JSX uses className instead of class
<div className="container">Content</div>
// JSX uses camelCase for attributes
<input onClick={handleClick} onChange={handleChange} />
// JSX requires self-closing tags
<img src="image.jpg" alt="Description" />
<br />
<input type="text" />
// JSX can embed JavaScript expressions
<h1>Hello, {user.name}!</h1>
<div style={{color: 'red', fontSize: '16px'}}>
Dynamic content
</div>
๐ How JSX Works
JSX gets compiled to regular JavaScript function calls. Here's what happens under the hood:
<div className="greeting">
<h1>Hello, {name}!</h1>
<p>Welcome to React</p>
</div>
React.createElement(
'div',
{ className: 'greeting' },
React.createElement('h1', null, 'Hello, ', name, '!'),
React.createElement('p', null, 'Welcome to React')
);
Functional Components
Modern React uses functional components - JavaScript functions that return JSX. They're simple, easy to understand, and work great with React Hooks.
// Simple component with no props
function Welcome() {
return <h1>Welcome to our website!</h1>;
}
// Component with props
function Greeting({ name, age }) {
return (
<div>
<h2>Hello, {name}!</h2>
<p>You are {age} years old.</p>
</div>
);
}
// Component with conditional rendering
function UserStatus({ isLoggedIn, username }) {
return (
<div>
{isLoggedIn ? (
<p>Welcome back, {username}!</p>
) : (
<p>Please log in to continue.</p>
)}
</div>
);
}
๐ก Component Rules
- Component names must start with a capital letter (e.g.,
UserCard, notuserCard) - Components must return JSX (or null, string, number, or array)
- Components can only return one root element (use fragments
<></>or<div>wrapper) - Props are read-only - never modify them directly
Class Components (Legacy)
Before functional components and hooks, React used class components. You'll still see them in older codebases, so it's good to understand them.
import React, { Component } from 'react';
class Greeting extends Component {
constructor(props) {
super(props);
this.state = {
message: 'Hello!'
};
}
render() {
return (
<div>
<h1>{this.state.message}</h1>
<p>Welcome, {this.props.name}!</p>
</div>
);
}
}
import React, { useState } from 'react';
function Greeting({ name }) {
const [message, setMessage] = useState('Hello!');
return (
<div>
<h1>{message}</h1>
<p>Welcome, {name}!</p>
</div>
);
}
๐ Why Functional Components?
- Simpler syntax - Less boilerplate code
- Better performance - Easier to optimize
- Hooks compatibility - Access to modern React features
- Easier testing - Pure functions are easier to test
Component Composition
One of React's superpowers is component composition - building complex UIs by combining simple components.
// Small, focused components
function Avatar({ src, alt }) {
return <img src={src} alt={alt} className="avatar" />;
}
function UserInfo({ name, email }) {
return (
<div className="user-info">
<h3>{name}</h3>
<p>{email}</p>
</div>
);
}
function ActionButton({ onClick, children }) {
return (
<button className="action-btn" onClick={onClick}>
{children}
</button>
);
}
// Composed component using smaller components
function UserCard({ user, onFollow, onMessage }) {
return (
<div className="user-card">
<Avatar src={user.avatar} alt={user.name} />
<UserInfo name={user.name} email={user.email} />
<div className="actions">
<ActionButton onClick={() => onFollow(user.id)}>
Follow
</ActionButton>
<ActionButton onClick={() => onMessage(user.id)}>
Message
</ActionButton>
</div>
</div>
);
}
๐ง Reusability
Small components can be reused across different parts of your application.
๐งช Testability
Small components are easier to test in isolation.
๐ Maintainability
When each component has a single responsibility, bugs are easier to find and fix.
๐ฅ Team Collaboration
Different team members can work on different components simultaneously.
JSX Best Practices
โ Do's and Don'ts
โ Good Practices:
// Use descriptive component names
function UserProfileCard({ user }) { /* ... */ }
// Use fragments to avoid unnecessary divs
function App() {
return (
<>
<Header />
<MainContent />
<Footer />
</>
);
}
// Use meaningful prop names
<Button
isLoading={isSubmitting}
disabled={!isFormValid}
onClick={handleSubmit}
>
Submit
</Button>
// Extract complex expressions
function TodoItem({ todo }) {
const isOverdue = new Date(todo.dueDate) < new Date();
return (
<div className={isOverdue ? 'overdue' : 'normal'}>
{todo.title}
</div>
);
}
โ Avoid:
// Don't modify props
function BadComponent({ user }) {
user.name = user.name.toUpperCase(); // โ Never do this
return <div>{user.name}</div>;
}
// Don't use array indices as keys (unless list never changes)
{items.map((item, index) =>
<Item key={index} data={item} /> // โ Avoid
)}
// Don't put complex logic in JSX
<div>
{/* โ Too complex */}
{user.posts.filter(post => post.published)
.sort((a, b) => new Date(b.date) - new Date(a.date))
.slice(0, 5)
.map(post => <Post key={post.id} post={post} />)}
</div>
What's Next?
Now that you understand components and JSX, you're ready to learn how components communicate with each other and manage their internal state.
๐ Continue Learning
- Props & State - Learn how data flows in React
- Event Handling - Make your components interactive
- Conditional Rendering - Show different content based on conditions
- React Hooks - Modern state management and side effects