Skip to content

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

  1. Prefer function components: More concise, better performance
  2. Keep components single-responsibility: Each component does one thing
  3. Use Props reasonably: Keep interface simple and clear
  4. Name components clearly: Use PascalCase naming
  5. Use memo appropriately: Avoid unnecessary re-renders

Continue Learning: Next Chapter - React Props

Content is for learning and research only.