React.js Mastery Guide
Complete guide from basics to advanced patterns
The Complete React.js Mastery Guide
Master modern React development with hooks, state management, and advanced patterns for building scalable web applications
Understanding React: The Modern UI Library
React is a declarative, component-based JavaScript library for building user interfaces. Created by Facebook in 2013, React revolutionized frontend development with its virtual DOM, component architecture, and unidirectional data flow. It powers millions of web applications from startups to enterprise-level systems.
What makes React unique is its component-based architecture that promotes reusability and maintainability. With the introduction of hooks in React 16.8, functional components became fully-featured, making React more intuitive and powerful than ever before.
Industry Standard: React is used by companies like Facebook, Instagram, Netflix, Airbnb, and Uber. Its vast ecosystem, strong community, and job market demand make it an essential skill for modern web developers.
1. React Basics & Components
Hello World: Your First React Component
// App.js - Main component import React from 'react'; // Functional Component function App() { return ( <div className="app"> <h1>Hello, React World!</h1> <p>Welcome to React programming</p> <WelcomeMessage name="Alice" /> </div> ); } // Component with props function WelcomeMessage({ name }) { return ( <div className="welcome"> <h2>Welcome, {name}!</h2> <p>Today is {new Date().toLocaleDateString()}</p> </div> ); } // Arrow function component const Button = ({ onClick, children }) => { return ( <button className="btn btn-primary" onClick={onClick} > {children} </button> ); }; export default App; // index.js - Entry point import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import './index.css'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <App /> </React.StrictMode> );
JSX Syntax and Expressions
import React from 'react'; function JSXExamples() { const userName = "John Doe"; const isLoggedIn = true; const userAge = 25; const fruits = ['Apple', 'Banana', 'Orange']; const user = { name: 'Alice', email: 'alice@example.com' }; return ( <div className="jsx-examples"> {/* Variables in JSX */} <h1>Hello, {userName}!</h1> {/* Conditional rendering */} {isLoggedIn ? ( <p>Welcome back!</p> ) : ( <p>Please log in</p> )} {/* Short-circuit evaluation */} {isLoggedIn && <p>You are logged in</p>} {/* Array rendering */} <ul> {fruits.map((fruit, index) => ( <li key={index}>{fruit}</li> ))} </ul> {/* Object properties */} <p>Name: {user.name}, Email: {user.email}</p> {/* Inline styles */} <div style={{ padding: '20px', backgroundColor: '#f0f0f0', borderRadius: '8px' }}> Styled div </div> {/* CSS classes */} <div className={`box ${isLoggedIn ? 'active' : 'inactive'}`}> Dynamic classes </div> {/* Event handlers */} <button onClick={() => alert('Button clicked!')}> Click me </button> </div> ); } export default JSXExamples;
Props: Passing Data Between Components
import React from 'react'; // Parent component function UserDashboard() { const user = { name: 'Alice Johnson', role: 'Developer', joinDate: '2023-01-15', avatar: 'https://example.com/avatar.jpg' }; const posts = [ { id: 1, title: 'React Basics', likes: 42 }, { id: 2, title: 'State Management', likes: 31 }, { id: 3, title: 'Hooks Deep Dive', likes: 56 } ]; return ( <div className="dashboard"> <UserProfile user={user} showAvatar={true} onUpdate={() => console.log('Profile updated')} /> <PostList posts={posts} emptyMessage="No posts yet" renderItem={(post) => ( <PostCard key={post.id} title={post.title} likes={post.likes} onLike={() => console.log('Liked:', post.id)} /> )} /> </div> ); } // Child component with props function UserProfile({ user, showAvatar, onUpdate }) { return ( <div className="user-profile"> {showAvatar && ( <img src={user.avatar} alt={user.name} className="avatar" /> )} <div className="user-info"> <h2>{user.name}</h2> <p>Role: {user.role}</p> <p>Joined: {new Date(user.joinDate).toLocaleDateString()}</p> </div> <button onClick={onUpdate}> Update Profile </button> </div> ); } // Component with default props function PostCard({ title, likes = 0, onLike }) { return ( <div className="post-card"> <h3>{title}</h3> <div className="post-actions"> <span>{likes} likes</span> <button onClick={onLike}>Like</button> </div> </div> ); } // Component with children prop function Container({ children, className = '' }) { return ( <div className={`container ${className}`}> {children} </div> ); } // List component with render props function PostList({ posts, emptyMessage, renderItem }) { if (posts.length === 0) { return <p>{emptyMessage}</p>; } return ( <div className="post-list"> {posts.map(renderItem)} </div> ); } export default UserDashboard;
Component Composition and Reusability
import React from 'react'; // Reusable Button component function Button({ variant = 'primary', size = 'medium', disabled = false, onClick, children }) { const baseClasses = 'btn'; const variantClass = `btn-${variant}`; const sizeClass = `btn-${size}`; const disabledClass = disabled ? 'btn-disabled' : ''; return ( <button className={`${baseClasses} ${variantClass} ${sizeClass} ${disabledClass}`} onClick={onClick} disabled={disabled} > {children} </button> ); } // Card component function Card({ header, footer, children }) { return ( <div className="card"> {header && <div className="card-header">{header}</div>} <div className="card-body">{children}</div> {footer && <div className="card-footer">{footer}</div>} </div> ); } // Modal component function Modal({ isOpen, onClose, title, children }) { if (!isOpen) return null; return ( <div className="modal-overlay"> <div className="modal"> <div className="modal-header"> <h3>{title}</h3> <button onClick={onClose} className="close-btn">Ć</button> </div> <div className="modal-content"> {children} </div> </div> </div> ); } // Using composition to build complex UI function ProductPage() { const [showModal, setShowModal] = React.useState(false); return ( <div className="product-page"> <Card header={<h2>Amazing Product</h2>} footer={ <div className="card-actions"> <Button variant="primary" onClick={() => setShowModal(true)}> Buy Now </Button> <Button variant="outline"> Add to Wishlist </Button> </div> } > <p>This is an amazing product description.</p> <ul> <li>Feature 1</li> <li>Feature 2</li> <li>Feature 3</li> </ul> </Card> <Modal isOpen={showModal} onClose={() => setShowModal(false)} title="Confirm Purchase" > <p>Are you sure you want to buy this product?</p> <div className="modal-actions"> <Button variant="primary" onClick={() => { console.log('Purchase confirmed'); setShowModal(false); }}> Confirm </Button> <Button variant="outline" onClick={() => setShowModal(false)}> Cancel </Button> </div> </Modal> </div> ); } export default ProductPage;
2. React Hooks
useState: Managing Component State
import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); const [step, setStep] = useState(1); const increment = () => setCount(count + step); const decrement = () => setCount(count - step); const reset = () => setCount(0); return ( <div className="counter"> <h2>Counter: {count}</h2> <div className="controls"> <button onClick={decrement}>-</button> <button onClick={reset}>Reset</button> <button onClick={increment}>+</button> </div> <div className="step-control"> <label> Step: <input type="number" value={step} onChange={(e) => setStep(Number(e.target.value))} min="1" /> </label> </div> </div> ); } function TodoList() { const [todos, setTodos] = useState([]); const [inputValue, setInputValue] = useState(''); const addTodo = () => { if (inputValue.trim()) { setTodos([...todos, { id: Date.now(), text: inputValue, completed: false }]); setInputValue(''); } }; 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"> <h2>Todo List ({todos.length})</h2> <div className="add-todo"> <input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && addTodo()} placeholder="Add a new todo..." /> <button onClick={addTodo}>Add</button> </div> <ul> {todos.map(todo => ( <li key={todo.id} className={todo.completed ? 'completed' : ''}> <span onClick={() => toggleTodo(todo.id)}> {todo.text} </span> <button onClick={() => deleteTodo(todo.id)}>Delete</button> </li> ))} </ul> </div> ); } function FormWithMultipleStates() { const [formData, setFormData] = useState({ name: '', email: '', age: '', subscribe: false }); const handleChange = (e) => { const { name, value, type, checked } = e.target; setFormData(prev => ({ ...prev, [name]: type === 'checkbox' ? checked : value })); }; const handleSubmit = (e) => { e.preventDefault(); console.log('Form submitted:', formData); }; return ( <form onSubmit={handleSubmit} className="user-form"> <input name="name" value={formData.name} onChange={handleChange} placeholder="Name" required /> <input name="email" type="email" value={formData.email} onChange={handleChange} placeholder="Email" required /> <input name="age" type="number" value={formData.age} onChange={handleChange} placeholder="Age" /> <label> <input name="subscribe" type="checkbox" checked={formData.subscribe} onChange={handleChange} /> Subscribe to newsletter </label> <button type="submit">Submit</button> </form> ); } export { Counter, TodoList, FormWithMultipleStates };
useEffect: Side Effects and Lifecycle
import React, { useState, useEffect } from 'react'; function DataFetcher() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Effect with cleanup useEffect(() => { let mounted = true; const fetchData = async () => { try { setLoading(true); const response = await fetch('https://api.example.com/data'); const result = await response.json(); if (mounted) { setData(result); setError(null); } } catch (err) { if (mounted) { setError('Failed to fetch data'); setData(null); } } finally { if (mounted) { setLoading(false); } } }; fetchData(); // Cleanup function return () => { mounted = false; }; }, []); // Empty dependency array = run once on mount if (loading) return <div>Loading...</div>; if (error) return <div>Error: {error}</div>; return ( <div> <h2>Fetched Data</h2> <pre>{JSON.stringify(data, null, 2)}</pre> </div> ); } function Timer() { const [time, setTime] = useState(new Date()); const [isRunning, setIsRunning] = useState(true); // Effect with dependency useEffect(() => { if (!isRunning) return; const interval = setInterval(() => { setTime(new Date()); }, 1000); // Cleanup interval on unmount or when isRunning changes return () => clearInterval(interval); }, [isRunning]); // Re-run when isRunning changes return ( <div className="timer"> <h2>Current Time: {time.toLocaleTimeString()}</h2> <button onClick={() => setIsRunning(!isRunning)}> {isRunning ? 'Pause' : 'Resume'} </button> </div> ); } function WindowSizeTracker() { const [windowSize, setWindowSize] = useState({ width: window.innerWidth, height: window.innerHeight }); // Effect for event listeners useEffect(() => { const handleResize = () => { setWindowSize({ width: window.innerWidth, height: window.innerHeight }); }; window.addEventListener('resize', handleResize); // Cleanup event listener return () => window.removeEventListener('resize', handleResize); }, []); // Empty array = setup and cleanup once return ( <div> <p>Window size: {windowSize.width} x {windowSize.height}</p> </div> ); } function UserProfile({ userId }) { const [user, setUser] = useState(null); // Effect that depends on props useEffect(() => { if (!userId) return; const fetchUser = async () => { const response = await fetch(`/api/users/${userId}`); const userData = await response.json(); setUser(userData); }; fetchUser(); }, [userId]); // Re-run when userId changes if (!user) return <div>Loading user...</div>; return ( <div> <h2>{user.name}</h2> <p>Email: {user.email}</p> </div> ); } export { DataFetcher, Timer, WindowSizeTracker, UserProfile };
Custom Hooks: Reusable Logic
import { useState, useEffect, useCallback } from 'react'; // Custom hook for API calls function useApi(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const refetch = useCallback(async () => { try { setLoading(true); setError(null); const response = await fetch(url); const result = await response.json(); setData(result); } catch (err) { setError(err.message); } finally { setLoading(false); } }, [url]); useEffect(() => { refetch(); }, [refetch]); return { data, loading, error, refetch }; } // Custom hook for local storage function useLocalStorage(key, initialValue) { const [storedValue, setStoredValue] = useState(() => { try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { console.error('Error reading from localStorage:', error); return initialValue; } }); const setValue = useCallback((value) => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.localStorage.setItem(key, JSON.stringify(valueToStore)); } catch (error) { console.error('Error saving to localStorage:', error); } }, [key, storedValue]); return [storedValue, setValue]; } // Custom hook for toggle functionality function useToggle(initialValue = false) { const [value, setValue] = useState(initialValue); const toggle = useCallback(() => setValue(prev => !prev), []); const setOn = useCallback(() => setValue(true), []); const setOff = useCallback(() => setValue(false), []); return [value, { toggle, setOn, setOff }]; } // Custom hook for debounced values function useDebounce(value, delay) { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value); }, delay); return () => { clearTimeout(handler); }; }, [value, delay]); return debouncedValue; } // Using custom hooks in components function UserSettings() { const [theme, setTheme] = useLocalStorage('theme', 'light'); const [isDarkMode, { toggle }] = useToggle(theme === 'dark'); useEffect(() => { const newTheme = isDarkMode ? 'dark' : 'light'; setTheme(newTheme); document.documentElement.setAttribute('data-theme', newTheme); }, [isDarkMode, setTheme]); return ( <div className="user-settings"> <h2>Settings</h2> <label> <input type="checkbox" checked={isDarkMode} onChange={toggle} /> Dark Mode </label> </div> ); } function SearchComponent() { const [query, setQuery] = useState(''); const debouncedQuery = useDebounce(query, 500); const { data: results, loading } = useApi( debouncedQuery ? `/api/search?q=${debouncedQuery}` : '' ); return ( <div className="search"> <input type="text" value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search..." /> {loading && <div>Searching...</div>} {results && ( <ul> {results.map(item => ( <li key={item.id}>{item.name}</li> ))} </ul> )} </div> ); } export { useApi, useLocalStorage, useToggle, useDebounce, UserSettings, SearchComponent };
3. State Management
useReducer: Complex State Logic
import React, { useReducer } from 'react'; // Reducer function function todoReducer(state, action) { switch (action.type) { case 'ADD_TODO': return { ...state, todos: [...state.todos, { id: Date.now(), text: action.text, completed: false }] }; case 'TOGGLE_TODO': return { ...state, todos: state.todos.map(todo => todo.id === action.id ? { ...todo, completed: !todo.completed } : todo ) }; case 'DELETE_TODO': return { ...state, todos: state.todos.filter(todo => todo.id !== action.id) }; case 'SET_FILTER': return { ...state, filter: action.filter }; case 'CLEAR_COMPLETED': return { ...state, todos: state.todos.filter(todo => !todo.completed) }; default: return state; } } const initialState = { todos: [], filter: 'all' // all, active, completed }; function TodoApp() { const [state, dispatch] = useReducer(todoReducer, initialState); const { todos, filter } = state; const addTodo = (text) => { if (text.trim()) { dispatch({ type: 'ADD_TODO', text }); } }; const filteredTodos = todos.filter(todo => { switch (filter) { case 'active': return !todo.completed; case 'completed': return todo.completed; default: return true; } }); return ( <div className="todo-app"> <h1>Todo App (useReducer)</h1> <TodoInput onAdd={addTodo} /> <div className="filters"> {['all', 'active', 'completed'].map(filterType => ( <button key={filterType} onClick={() => dispatch({ type: 'SET_FILTER', filter: filterType })} className={filter === filterType ? 'active' : ''} > {filterType} </button> ))} </div> <TodoList todos={filteredTodos} onToggle={id => dispatch({ type: 'TOGGLE_TODO', id })} onDelete={id => dispatch({ type: 'DELETE_TODO', id })} /> <button onClick={() => dispatch({ type: 'CLEAR_COMPLETED' })} className="clear-btn" > Clear Completed </button> </div> ); } function TodoInput({ onAdd }) { const [text, setText] = React.useState(''); const handleSubmit = (e) => { e.preventDefault(); onAdd(text); setText(''); }; return ( <form onSubmit={handleSubmit} className="todo-input"> <input type="text" value={text} onChange={(e) => setText(e.target.value)} placeholder="Add a new todo..." /> <button type="submit">Add</button> </form> ); } function TodoList({ todos, onToggle, onDelete }) { return ( <ul className="todo-list"> {todos.map(todo => ( <li key={todo.id} className={todo.completed ? 'completed' : ''}> <span onClick={() => onToggle(todo.id)}> {todo.text} </span> <button onClick={() => onDelete(todo.id)}>Delete</button> </li> ))} </ul> ); } // Shopping Cart Example with useReducer function cartReducer(state, action) { switch (action.type) { case 'ADD_ITEM': const existingItem = state.items.find(item => item.id === action.item.id); if (existingItem) { return { ...state, items: state.items.map(item => item.id === action.item.id ? { ...item, quantity: item.quantity + 1 } : item ) }; } return { ...state, items: [...state.items, { ...action.item, quantity: 1 }] }; case 'REMOVE_ITEM': return { ...state, items: state.items.filter(item => item.id !== action.id) }; case 'UPDATE_QUANTITY': return { ...state, items: state.items.map(item => item.id === action.id ? { ...item, quantity: action.quantity } : item ) }; case 'CLEAR_CART': return { ...state, items: [] }; default: return state; } } function ShoppingCart() { const [state, dispatch] = useReducer(cartReducer, { items: [] }); const total = state.items.reduce( (sum, item) => sum + item.price * item.quantity, 0 ); return ( <div className="shopping-cart"> <h2>Shopping Cart</h2> {state.items.length === 0 ? ( <p>Your cart is empty</p> ) : ( <> {state.items.map(item => ( <div key={item.id} className="cart-item"> <span>{item.name}</span> <input type="number" value={item.quantity} onChange={(e) => dispatch({ type: 'UPDATE_QUANTITY', id: item.id, quantity: parseInt(e.target.value) })} min="1" /> <span>${(item.price * item.quantity).toFixed(2)}</span> <button onClick={() => dispatch({ type: 'REMOVE_ITEM', id: item.id })}> Remove </button> </div> ))} <div className="cart-total"> Total: ${total.toFixed(2)} </div> <button onClick={() => dispatch({ type: 'CLEAR_CART' })}> Clear Cart </button> </> )} </div> ); } export { TodoApp, ShoppingCart };
Context API: Global State Management
import React, { createContext, useContext, useReducer } from 'react'; // Create Context const AuthContext = createContext(); // Auth reducer function authReducer(state, action) { switch (action.type) { case 'LOGIN': return { ...state, user: action.user, isAuthenticated: true }; case 'LOGOUT': return { ...state, user: null, isAuthenticated: false }; case 'UPDATE_USER': return { ...state, user: { ...state.user, ...action.updates } }; default: return state; } } const initialState = { user: null, isAuthenticated: false }; // Context Provider function AuthProvider({ children }) { const [state, dispatch] = useReducer(authReducer, initialState); const login = (user) => dispatch({ type: 'LOGIN', user }); const logout = () => dispatch({ type: 'LOGOUT' }); const updateUser = (updates) => dispatch({ type: 'UPDATE_USER', updates }); const value = { ...state, login, logout, updateUser }; return ( <AuthContext.Provider value={value}> {children} </AuthContext.Provider> ); } // Custom hook to use auth context function useAuth() { const context = useContext(AuthContext); if (!context) { throw new Error('useAuth must be used within an AuthProvider'); } return context; } // Components using the context function LoginForm() { const { login } = useAuth(); const [credentials, setCredentials] = React.useState({ email: '', password: '' }); const handleSubmit = (e) => { e.preventDefault(); // Simulate login login({ id: 1, name: 'John Doe', email: credentials.email }); }; return ( <form onSubmit={handleSubmit} className="login-form"> <input type="email" value={credentials.email} onChange={(e) => setCredentials(prev => ({ ...prev, email: e.target.value }))} placeholder="Email" required /> <input type="password" value={credentials.password} onChange={(e) => setCredentials(prev => ({ ...prev, password: e.target.value }))} placeholder="Password" required /> <button type="submit">Login</button> </form> ); } function UserProfile() { const { user, updateUser } = useAuth(); if (!user) return null; return ( <div className="user-profile"> <h2>Welcome, {user.name}!</h2> <p>Email: {user.email}</p> <button onClick={() => updateUser({ name: 'Jane Doe' })}> Update Name </button> </div> ); } function Header() { const { user, isAuthenticated, logout } = useAuth(); return ( <header className="app-header"> <h1>My App</h1> <div className="user-info"> {isAuthenticated ? ( <> <span>Hello, {user?.name}</span> <button onClick={logout}>Logout</button> </> ) : ( <span>Please log in</span> )} </div> </header> ); } // Main App component function App() { return ( <AuthProvider> <div className="app"> <Header /> <main> <AuthWrapper /> </main> </div> </AuthProvider> ); } function AuthWrapper() { const { isAuthenticated } = useAuth(); return ( <div className="auth-wrapper"> {isAuthenticated ? <UserProfile /> : <LoginForm />} </div> ); } // Theme Context Example const ThemeContext = createContext(); function ThemeProvider({ children }) { const [theme, setTheme] = React.useState('light'); const toggleTheme = () => { setTheme(prev => prev === 'light' ? 'dark' : 'light'); }; return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> <div data-theme={theme}> {children} </div> </ThemeContext.Provider> ); } function useTheme() { const context = useContext(ThemeContext); if (!context) { throw new Error('useTheme must be used within a ThemeProvider'); } return context; } function ThemeToggle() { const { theme, toggleTheme } = useTheme(); return ( <button onClick={toggleTheme} className="theme-toggle"> Switch to {theme === 'light' ? 'Dark' : 'Light'} Mode </button> ); } export { App, ThemeProvider, ThemeToggle, useAuth, useTheme };
š» React Practice Projects
Beginner Level
- 1Build a Todo List App with useState and useEffect
- 2Create a Weather App with API integration
- 3Implement a Calculator with component composition
- 4Build a Markdown Previewer with real-time updates
- 5Create a Shopping Cart with state management
Intermediate Level
- 1Develop a Blog Platform with React Router
- 2Build a Real-time Chat App with WebSockets
- 3Create a Dashboard with charts and data visualization
- 4Implement a Drag-and-drop Task Board
- 5Build a Social Media Feed with infinite scrolling
Advanced Level
- 1Create a Micro-frontend Architecture
- 2Build a Design System with Storybook
- 3Implement Server-side Rendering with Next.js
- 4Develop a Progressive Web App (PWA)
- 5Build a Real-time Collaborative Editor
š React Quick Reference
Essential Hooks
- ā¢useState - Component state
- ā¢useEffect - Side effects
- ā¢useContext - Global state
- ā¢useReducer - Complex state
- ā¢useCallback - Memoized functions
- ā¢useMemo - Memoized values
- ā¢useRef - DOM references
Common Patterns
- ā¢Component Composition
- ā¢Render Props
- ā¢Higher-Order Components
- ā¢Custom Hooks
- ā¢Context API
- ā¢Error Boundaries
- ā¢Code Splitting
Master Modern Web Development!
React has revolutionized how we build user interfaces, making it possible to create highly interactive and performant web applications. Its component-based architecture and rich ecosystem make it the most popular frontend library in the world.
With modern React features like hooks, context, and concurrent features, you can build applications that are more maintainable, testable, and scalable than ever before.