React Component Basics
Overview
Components are the basic building blocks of React applications. Every React application is a component tree composed of components. This chapter will learn how to create and use React components, including function components, class components, and component composition.
🧩 What is a Component
Basic Component Concepts
jsx
// Simplest function component
function Welcome() {
return <h1>Hello, World!</h1>;
}
// Using components
function App() {
return (
<div>
<Welcome />
<Welcome />
<Welcome />
</div>
);
}Component Characteristics
- Reusable: Define once, use multiple times
- Independent: Each component manages its own state
- Composable: Small components combine into large components
- Declarative: Describe what the UI should look like
📝 Function Components
Basic Function Components
jsx
// Component without parameters
function Header() {
return (
<header>
<h1>My Website</h1>
<nav>
<a href="#home">Home</a>
<a href="#about">About</a>
<a href="#contact">Contact</a>
</nav>
</header>
);
}
// Component with parameters
function Greeting({ name, time = "Morning" }) {
return (
<div>
<h2>Good {time}, {name}!</h2>
<p>Welcome to our website</p>
</div>
);
}
// Using components
function App() {
return (
<div>
<Header />
<Greeting name="John" time="Afternoon" />
<Greeting name="Jane" />
</div>
);
}Arrow Function Components
jsx
// Arrow function syntax
const Button = ({ children, onClick, type = "button" }) => {
return (
<button type={type} onClick={onClick}>
{children}
</button>
);
};
const Card = ({ title, content, imageUrl }) => (
<div className="card">
{imageUrl && <img src={imageUrl} alt={title} />}
<h3>{title}</h3>
<p>{content}</p>
</div>
);
// Component composition
const ProductCard = ({ product }) => (
<Card
title={product.name}
content={product.description}
imageUrl={product.image}
/>
);🏗️ Class Components
Basic Class Components
jsx
import React, { Component } from 'react';
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<h2>Counter: {this.state.count}</h2>
<button onClick={this.increment}>
Increment
</button>
</div>
);
}
}
// Class component with lifecycle
class Timer extends Component {
constructor(props) {
super(props);
this.state = {
seconds: 0
};
}
componentDidMount() {
this.interval = setInterval(() => {
this.setState({ seconds: this.state.seconds + 1 });
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div>
<h3>Elapsed: {this.state.seconds} seconds</h3>
</div>
);
}
}🔧 Props and Children
Props Passing
jsx
function UserProfile({ user, showEmail = false, onEdit }) {
return (
<div className="user-profile">
<h2>{user.name}</h2>
<p>Age: {user.age}</p>
{showEmail && <p>Email: {user.email}</p>}
<button onClick={() => onEdit(user.id)}>
Edit
</button>
</div>
);
}
// Using Props
function App() {
const user = {
id: 1,
name: "John",
age: 25,
email: "john@example.com"
};
const handleEdit = (userId) => {
console.log(`Edit user: ${userId}`);
};
return (
<UserProfile
user={user}
showEmail={true}
onEdit={handleEdit}
/>
);
}Children Property
jsx
function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;
return (
<div className="modal-overlay">
<div className="modal">
<button className="modal-close" onClick={onClose}>
×
</button>
{children}
</div>
</div>
);
}
function ConfirmDialog({ isOpen, onClose, onConfirm }) {
return (
<Modal isOpen={isOpen} onClose={onClose}>
<h3>Confirm Action</h3>
<p>Are you sure you want to perform this action?</p>
<div className="modal-actions">
<button onClick={onConfirm}>Confirm</button>
<button onClick={onClose}>Cancel</button>
</div>
</Modal>
);
}🎯 Component Composition Patterns
Container and Presentational Components
jsx
// Presentational component (only responsible for UI)
function TodoItem({ todo, onToggle, onDelete }) {
return (
<div className={`todo-item ${todo.completed ? 'completed' : ''}`}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => onToggle(todo.id)}
/>
<span>{todo.text}</span>
<button onClick={() => onDelete(todo.id)}>Delete</button>
</div>
);
}
// Container component (manages state and logic)
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: 'Learn React', completed: false },
{ id: 2, text: 'Write Documentation', completed: true }
]);
const toggleTodo = (id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
const deleteTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
return (
<div className="todo-list">
{todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={toggleTodo}
onDelete={deleteTodo}
/>
))}
</div>
);
}Higher-Order Component Pattern
jsx
// Loading state higher-order component
function withLoading(WrappedComponent) {
return function WithLoadingComponent({ isLoading, ...props }) {
if (isLoading) {
return <div className="loading">Loading...</div>;
}
return <WrappedComponent {...props} />;
};
}
// Using higher-order component
const UserListWithLoading = withLoading(function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
});
function App() {
const [users, setUsers] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setUsers([
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
]);
setIsLoading(false);
}, 2000);
}, []);
return (
<UserListWithLoading
users={users}
isLoading={isLoading}
/>
);
}🎨 Component Styling
CSS Modules
jsx
// Button.module.css
/*
.button {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.primary {
background-color: #007bff;
color: white;
}
.secondary {
background-color: #6c757d;
color: white;
}
*/
import styles from './Button.module.css';
function Button({ variant = 'primary', children, ...props }) {
const buttonClass = `${styles.button} ${styles[variant]}`;
return (
<button className={buttonClass} {...props}>
{children}
</button>
);
}Styled Components
jsx
import styled from 'styled-components';
const StyledButton = styled.button`
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
background-color: ${props =>
props.variant === 'primary' ? '#007bff' : '#6c757d'
};
color: white;
&:hover {
opacity: 0.8;
}
`;
function Button({ variant, children, ...props }) {
return (
<StyledButton variant={variant} {...props}>
{children}
</StyledButton>
);
}📊 Component Performance Optimization
React.memo
jsx
import { memo } from 'react';
const ExpensiveComponent = memo(function ExpensiveComponent({ data, filter }) {
console.log('ExpensiveComponent rendered');
const filteredData = data.filter(item =>
item.name.toLowerCase().includes(filter.toLowerCase())
);
return (
<ul>
{filteredData.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
});
// Custom comparison function
const CustomMemoComponent = memo(function Component({ user, settings }) {
return (
<div>
<h2>{user.name}</h2>
<p>Theme: {settings.theme}</p>
</div>
);
}, (prevProps, nextProps) => {
return prevProps.user.id === nextProps.user.id &&
prevProps.settings.theme === nextProps.settings.theme;
});📝 Chapter Summary
Components are the core concept of React. Through this chapter, you should have mastered:
Key Takeaways
- ✅ How to create function components and class components
- ✅ Props passing and usage
- ✅ Children property application
- ✅ Component composition and reuse patterns
- ✅ Component styling management
- ✅ Basic performance optimization techniques
Best Practices
- Prefer function components: More concise, better performance
- Keep components single-responsibility: Each component does one thing
- Use Props reasonably: Keep interface simple and clear
- Name components clearly: Use PascalCase naming
- Use memo appropriately: Avoid unnecessary re-renders
Continue Learning: Next Chapter - React Props