What is Hadoop Cluster: Complete Guide to Distributed Big Data Processing
Welcome to this comprehensive ReactJS tutorial designed to take you from complete beginner to confident React developer. This ReactJS tutorial covers everything you need to build modern, interactive web applications using React—the most popular JavaScript library for building user interfaces. Whether you’re starting your coding journey or transitioning from other frameworks, this ReactJS tutorial provides clear explanations, practical examples, and hands-on exercises that build real-world development skills.
Throughout this ReactJS tutorial, you’ll learn fundamental concepts including components, JSX, props, state, hooks, and event handling before progressing to advanced topics like performance optimization, custom hooks, context API, and modern React patterns. Each section includes code examples you can run and modify, reinforcing learning through practice. By the end of this ReactJS tutorial, you’ll have built multiple projects demonstrating mastery of React development principles and best practices.
This ReactJS tutorial reflects current React best practices for 2026, focusing on modern functional components and hooks rather than outdated class component patterns. You’ll learn the same techniques used by professional developers at leading technology companies, preparing you for real-world React development or job opportunities in the rapidly growing React ecosystem.
Getting Started with React
What is React and Why Learn It?
Before diving into this ReactJS tutorial, understanding what makes React special helps appreciate why millions of developers choose it.
React is:
- A JavaScript library for building user interfaces
- Developed and maintained by Facebook (Meta)
- Component-based, promoting code reusability
- Declarative, making code predictable and easier to debug
- Focused on the view layer (the “V” in MVC)
Why Learn React:
Industry Demand: React developers are highly sought-after with excellent salaries. Most modern web applications use React or similar component-based frameworks.
Rich Ecosystem: Thousands of libraries, tools, and resources support React development. From routing (React Router) to state management (Redux, Zustand) to UI components (Material-UI, Chakra), the ecosystem provides solutions for every need.
React Native: After learning React for web, you can build mobile apps using React Native with the same concepts and similar code.
Strong Community: Millions of developers worldwide use React, providing extensive learning resources, tutorials, open-source projects, and community support.
Modern Development: React embraces modern JavaScript features and best practices, teaching you skills applicable beyond React itself.
Setting Up Your Development Environment
This ReactJS tutorial begins with proper environment setup.
Prerequisites:
- Basic HTML, CSS, and JavaScript knowledge
- Computer with Windows, Mac, or Linux
- Text editor (VS Code recommended)
- Node.js and npm installed
Step 1: Install Node.js and npm
Visit nodejs.org and download the LTS version. Node.js includes npm (Node Package Manager) which manages React and other JavaScript packages.
Verify installation by opening terminal/command prompt:
node --version
npm --version
Step 2: Install VS Code (Recommended Editor)
Download from code.visualstudio.com
Recommended VS Code Extensions:
- ES7+ React/Redux/React-Native snippets
- Prettier – Code formatter
- ESLint
- Auto Rename Tag
- Bracket Pair Colorizer
Step 3: Create Your First React App
React provides Create React App, a tool that sets up everything you need:
npx create-react-app my-first-app
cd my-first-app
npm start
This creates a new React project and starts a development server. Your browser opens automatically showing the default React app at http://localhost:3000.
Project Structure:
my-first-app/
├── node_modules/ # Dependencies
├── public/ # Static files
│ └── index.html # HTML template
├── src/ # React code
│ ├── App.js # Main component
│ ├── App.css # Styles
│ └── index.js # Entry point
├── package.json # Project configuration
└── README.md # Documentation
Alternative: Vite (Faster Development)
For faster development experience:
npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install
npm run dev
Understanding React Project Structure
This ReactJS tutorial section explains key files in your React project.
public/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>React App</title>
</head>
<body>
<div id="root"></div>
<!-- React app injects here -->
</body>
</html>
src/index.js (Entry Point):
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
This file:
- Imports React and ReactDOM
- Imports your main App component
- Finds the
<div id="root">element - Renders the App component inside it
src/App.js (Main Component):
function App() {
return (
<div className="App">
<h1>Hello React!</h1>
<p>Welcome to your first React app</p>
</div>
);
}
export default App;
This defines your main component returning JSX (HTML-like syntax).
Your First React Component
Let’s create your first custom component in this ReactJS tutorial.
Create src/Welcome.js:
function Welcome() {
return (
<div>
<h2>Welcome to React!</h2>
<p>This is my first custom component</p>
</div>
);
}
export default Welcome;
Use it in App.js:
import Welcome from './Welcome';
function App() {
return (
<div className="App">
<Welcome />
</div>
);
}
export default App;
Key Points:
- Components are JavaScript functions (or classes)
- Component names start with capital letters
- Components return JSX
- Import components before using them
- Self-closing tags:
<Welcome />or<Welcome></Welcome>
Save the files and see your component render automatically!
JSX: JavaScript XML
Introduction to JSX
JSX is crucial in this ReactJS tutorial—it’s how you write HTML-like code in JavaScript.
What is JSX:
- JavaScript syntax extension
- Looks like HTML but is actually JavaScript
- Transpiled to JavaScript by Babel
- Not required but highly recommended
JSX vs HTML:
HTML:
<div class="container">
<h1>Hello World</h1>
</div>
JSX:
<div className="container">
<h1>Hello World</h1>
</div>
Notice className instead of class (because class is reserved in JavaScript).
Under the Hood:
JSX:
const element = <h1>Hello, world!</h1>;
Transpiles to:
const element = React.createElement('h1', null, 'Hello, world!');
JSX Rules and Syntax
This ReactJS tutorial section covers essential JSX rules.
Rule 1: Single Parent Element
❌ Wrong:
function App() {
return (
<h1>Hello</h1>
<p>World</p>
);
}
✅ Correct:
function App() {
return (
<div>
<h1>Hello</h1>
<p>World</p>
</div>
);
}
Or use Fragments:
function App() {
return (
<>
<h1>Hello</h1>
<p>World</p>
</>
);
}
Rule 2: Close All Tags
// Self-closing tags
<img src="photo.jpg" />
<input type="text" />
<br />
// Regular tags
<div></div>
<button></button>
Rule 3: Use camelCase for Attributes
// HTML attributes become camelCase
className // instead of class
htmlFor // instead of for
onClick // instead of onclick
onChange // instead of onchange
Rule 4: JavaScript Expressions in Curly Braces
function Greeting() {
const name = "John";
const age = 25;
return (
<div>
<h1>Hello {name}!</h1>
<p>You are {age} years old</p>
<p>Next year you'll be {age + 1}</p>
</div>
);
}
Embedding JavaScript Expressions
This ReactJS tutorial shows how to embed dynamic content in JSX.
Variables:
function UserInfo() {
const user = {
firstName: "Jane",
lastName: "Doe",
age: 28
};
return (
<div>
<h2>{user.firstName} {user.lastName}</h2>
<p>Age: {user.age}</p>
</div>
);
}
Expressions:
function Calculator() {
const a = 5;
const b = 10;
return (
<div>
<p>{a} + {b} = {a + b}</p>
<p>{a} × {b} = {a * b}</p>
<p>Is {a} greater than {b}? {a > b ? 'Yes' : 'No'}</p>
</div>
);
}
Function Calls:
function formatDate(date) {
return date.toLocaleDateString();
}
function DateDisplay() {
return (
<div>
<p>Today is {formatDate(new Date())}</p>
</div>
);
}
Conditional Rendering:
function Greeting({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? (
<h1>Welcome back!</h1>
) : (
<h1>Please sign in</h1>
)}
</div>
);
}
Styling in JSX
This ReactJS tutorial covers different ways to style React components.
Inline Styles (Object):
function StyledComponent() {
const divStyle = {
color: 'blue',
backgroundColor: 'lightgray',
padding: '10px',
borderRadius: '5px'
};
return (
<div style={divStyle}>
<h2>Styled with inline styles</h2>
</div>
);
}
// Or directly
function DirectStyle() {
return (
<div style={{ color: 'red', fontSize: '20px' }}>
Direct inline style
</div>
);
}
CSS Classes:
// In App.css
/*
.card {
border: 1px solid #ddd;
padding: 20px;
border-radius: 8px;
}
.card-title {
color: #333;
font-size: 24px;
}
*/
// In component
import './App.css';
function Card() {
return (
<div className="card">
<h2 className="card-title">Card Title</h2>
<p>Card content goes here</p>
</div>
);
}
Conditional Classes:
function Button({ isPrimary }) {
const buttonClass = isPrimary ? 'btn btn-primary' : 'btn btn-secondary';
return (
<button className={buttonClass}>
Click Me
</button>
);
}
Components Deep Dive
Functional Components
Modern React uses functional components—the focus of this ReactJS tutorial.
Simple Functional Component:
function Greeting() {
return <h1>Hello, React!</h1>;
}
With Arrow Function:
const Greeting = () => {
return <h1>Hello, React!</h1>;
};
Implicit Return (No Braces):
const Greeting = () => <h1>Hello, React!</h1>;
Multi-Line JSX:
const UserCard = () => {
return (
<div className="user-card">
<img src="avatar.jpg" alt="User" />
<h2>John Doe</h2>
<p>Software Developer</p>
</div>
);
};
Component with Logic:
function Welcome() {
const user = {
name: "Alice",
age: 30
};
const canVote = user.age >= 18;
return (
<div>
<h1>Welcome, {user.name}!</h1>
<p>Voting eligibility: {canVote ? 'Yes' : 'No'}</p>
</div>
);
}
Props: Passing Data to Components
Props make components reusable—essential in any ReactJS tutorial.
Passing Props:
function App() {
return (
<div>
<Greeting name="Alice" age={25} />
<Greeting name="Bob" age={30} />
</div>
);
}
Receiving Props:
function Greeting(props) {
return (
<div>
<h2>Hello, {props.name}!</h2>
<p>You are {props.age} years old</p>
</div>
);
}
Destructuring Props:
function Greeting({ name, age }) {
return (
<div>
<h2>Hello, {name}!</h2>
<p>You are {age} years old</p>
</div>
);
}
Default Props:
function Greeting({ name = "Guest", age = 18 }) {
return (
<div>
<h2>Hello, {name}!</h2>
<p>Age: {age}</p>
</div>
);
}
// Usage
<Greeting name="Alice" age={25} />
<Greeting name="Bob" /> // age defaults to 18
<Greeting /> // name defaults to "Guest", age to 18
Passing Different Data Types:
function UserProfile({
name, // string
age, // number
isActive, // boolean
hobbies, // array
address, // object
onClick // function
}) {
return (
<div onClick={onClick}>
<h2>{name}</h2>
<p>Age: {age}</p>
<p>Status: {isActive ? 'Active' : 'Inactive'}</p>
<p>Hobbies: {hobbies.join(', ')}</p>
<p>City: {address.city}</p>
</div>
);
}
// Usage
<UserProfile
name="Alice"
age={28}
isActive={true}
hobbies={['reading', 'coding', 'hiking']}
address={{ city: 'New York', country: 'USA' }}
onClick={() => console.log('Profile clicked')}
/>
Props.children:
function Card({ children }) {
return (
<div className="card">
{children}
</div>
);
}
// Usage
<Card>
<h2>Card Title</h2>
<p>Card content goes here</p>
<button>Click Me</button>
</Card>
Component Composition
This ReactJS tutorial demonstrates building complex UIs from simple components.
Building Blocks:
function Avatar({ url }) {
return <img src={url} alt="Avatar" className="avatar" />;
}
function UserName({ name }) {
return <h3>{name}</h3>;
}
function UserBio({ bio }) {
return <p>{bio}</p>;
}
function UserCard({ user }) {
return (
<div className="user-card">
<Avatar url={user.avatarUrl} />
<UserName name={user.name} />
<UserBio bio={user.bio} />
</div>
);
}
// Usage
function App() {
const user = {
name: "John Doe",
avatarUrl: "avatar.jpg",
bio: "Software Developer"
};
return <UserCard user={user} />;
}
Container and Presentational Components:
// Presentational (only displays data)
function ProductCard({ product }) {
return (
<div className="product-card">
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<p>${product.price}</p>
</div>
);
}
// Container (manages data and logic)
function ProductList() {
const products = [
{ id: 1, name: 'Laptop', price: 999, image: 'laptop.jpg' },
{ id: 2, name: 'Phone', price: 699, image: 'phone.jpg' },
{ id: 3, name: 'Tablet', price: 499, image: 'tablet.jpg' }
];
return (
<div className="product-list">
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
Lists and Keys
Rendering lists efficiently is critical in this ReactJS tutorial.
Basic List Rendering:
function FruitList() {
const fruits = ['Apple', 'Banana', 'Orange', 'Mango'];
return (
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
);
}
Using Unique IDs (Better):
function TodoList() {
const todos = [
{ id: 1, text: 'Learn React', completed: true },
{ id: 2, text: 'Build a project', completed: false },
{ id: 3, text: 'Deploy app', completed: false }
];
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<input type="checkbox" checked={todo.completed} />
{todo.text}
</li>
))}
</ul>
);
}
Rendering Component Lists:
function UserItem({ user }) {
return (
<div className="user-item">
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
);
}
function UserList() {
const users = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
{ id: 3, name: 'Charlie', email: 'charlie@example.com' }
];
return (
<div>
{users.map(user => (
<UserItem key={user.id} user={user} />
))}
</div>
);
}
Why Keys Matter:
- Help React identify which items changed, added, or removed
- Optimize rendering performance
- Should be stable, unique, and consistent across re-renders
- Avoid using array index as key when items can be reordered
State Management with Hooks
Introduction to React Hooks
Hooks revolutionized React—central to this ReactJS tutorial.
What are Hooks:
- Functions that let you “hook into” React features
- Use state and lifecycle in functional components
- Introduced in React 16.8
- Start with “use” (useState, useEffect, etc.)
Hook Rules:
- Only call hooks at the top level (not inside loops, conditions, or nested functions)
- Only call hooks from React functions (components or custom hooks)
Most Common Hooks:
useState– Add state to componentsuseEffect– Perform side effectsuseContext– Access contextuseReducer– Complex state logicuseCallback– Memoize callbacksuseMemo– Memoize valuesuseRef– Reference values/DOM elements
useState: Managing Component State
useState is fundamental in this ReactJS tutorial.
Basic Usage:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
How it Works:
useState(0)initializes state with value0- Returns array with two elements:
[currentState, updaterFunction] countis the current state valuesetCountis the function to update state- When state updates, component re-renders
Multiple State Variables:
function UserForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [age, setAge] = useState(0);
return (
<form>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
/>
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
value={age}
onChange={(e) => setAge(Number(e.target.value))}
placeholder="Age"
type="number"
/>
</form>
);
}
State with Objects:
function UserProfile() {
const [user, setUser] = useState({
name: '',
email: '',
age: 0
});
const updateField = (field, value) => {
setUser(prevUser => ({
...prevUser,
[field]: value
}));
};
return (
<div>
<input
value={user.name}
onChange={(e) => updateField('name', e.target.value)}
/>
<input
value={user.email}
onChange={(e) => updateField('email', e.target.value)}
/>
</div>
);
}
State with Arrays:
function TodoApp() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const addTodo = () => {
setTodos([...todos, { id: Date.now(), text: input }]);
setInput('');
};
const removeTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
return (
<div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
/>
<button onClick={addTodo}>Add Todo</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.text}
<button onClick={() => removeTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
Functional Updates:
function Counter() {
const [count, setCount] = useState(0);
// When new state depends on previous state
const increment = () => {
setCount(prevCount => prevCount + 1);
};
// Multiple updates
const incrementByThree = () => {
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+1</button>
<button onClick={incrementByThree}>+3</button>
</div>
);
}
useEffect: Side Effects and Lifecycle
useEffect handles side effects in this ReactJS tutorial.
Basic useEffect:
import { useState, useEffect } from 'react';
function DocumentTitle() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
});
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
Also Read: ReactJS interview questions
useEffect with Dependency Array:
// Runs on every render
useEffect(() => {
console.log('Runs every render');
});
// Runs only on mount
useEffect(() => {
console.log('Runs once on mount');
}, []);
// Runs when count changes
useEffect(() => {
console.log('Count changed:', count);
}, [count]);
// Runs when count or name changes
useEffect(() => {
console.log('Count or name changed');
}, [count, name]);
Cleanup Function:
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
// Cleanup function
return () => {
clearInterval(interval);
};
}, []);
return <div>Seconds: {seconds}</div>;
}
Fetching Data:
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => {
setUsers(data);
setLoading(false);
})
.catch(error => {
console.error('Error:', error);
setLoading(false);
});
}, []);
if (loading) return <div>Loading...</div>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Multiple useEffects:
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [posts, setPosts] = useState([]);
// Fetch user data
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(setUser);
}, [userId]);
// Fetch user posts
useEffect(() => {
fetch(`/api/users/${userId}/posts`)
.then(r => r.json())
.then(setPosts);
}, [userId]);
// Update document title
useEffect(() => {
if (user) {
document.title = user.name;
}
}, [user]);
return (
<div>
{user && <h1>{user.name}</h1>}
{posts.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}
Event Handling
Handling Events in React
Event handling is crucial in this ReactJS tutorial.
Basic Event Handling:
function Button() {
const handleClick = () => {
alert('Button clicked!');
};
return (
<button onClick={handleClick}>
Click Me
</button>
);
}
Inline Event Handlers:
function InlineEvents() {
return (
<div>
<button onClick={() => alert('Clicked!')}>
Click Me
</button>
<button onClick={() => console.log('Logged!')}>
Log Me
</button>
</div>
);
}
Event Object:
function EventObject() {
const handleClick = (event) => {
console.log('Event type:', event.type);
console.log('Target:', event.target);
console.log('Current target:', event.currentTarget);
};
return (
<button onClick={handleClick}>
Click for Event Info
</button>
);
}
Common Events:
function Events() {
return (
<div>
{/* Click events */}
<button onClick={() => console.log('Clicked')}>Click</button>
<button onDoubleClick={() => console.log('Double clicked')}>
Double Click
</button>
{/* Mouse events */}
<div
onMouseEnter={() => console.log('Mouse entered')}
onMouseLeave={() => console.log('Mouse left')}
>
Hover me
</div>
{/* Form events */}
<input
onChange={(e) => console.log('Input:', e.target.value)}
onFocus={() => console.log('Focused')}
onBlur={() => console.log('Blurred')}
/>
<form onSubmit={(e) => {
e.preventDefault();
console.log('Form submitted');
}}>
<button type="submit">Submit</button>
</form>
{/* Keyboard events */}
<input
onKeyDown={(e) => console.log('Key down:', e.key)}
onKeyUp={(e) => console.log('Key up:', e.key)}
onKeyPress={(e) => console.log('Key press:', e.key)}
/>
</div>
);
}
Form Handling
Forms are essential in any ReactJS tutorial.
Controlled Input:
function ControlledInput() {
const [value, setValue] = useState('');
return (
<div>
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<p>You typed: {value}</p>
</div>
);
}
Complete Form:
function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: ''
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form submitted:', formData);
// Reset form
setFormData({ name: '', email: '', message: '' });
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Name:</label>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
required
/>
</div>
<div>
<label>Email:</label>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
required
/>
</div>
<div>
<label>Message:</label>
<textarea
name="message"
value={formData.message}
onChange={handleChange}
required
/>
</div>
<button type="submit">Submit</button>
</form>
);
}
Checkbox and Radio:
function FormInputs() {
const [checked, setChecked] = useState(false);
const [selected, setSelected] = useState('');
const [gender, setGender] = useState('');
return (
<div>
{/* Checkbox */}
<label>
<input
type="checkbox"
checked={checked}
onChange={(e) => setChecked(e.target.checked)}
/>
Accept terms
</label>
{/* Select dropdown */}
<select
value={selected}
onChange={(e) => setSelected(e.target.value)}
>
<option value="">Choose...</option>
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
</select>
{/* Radio buttons */}
<div>
<label>
<input
type="radio"
value="male"
checked={gender === 'male'}
onChange={(e) => setGender(e.target.value)}
/>
Male
</label>
<label>
<input
type="radio"
value="female"
checked={gender === 'female'}
onChange={(e) => setGender(e.target.value)}
/>
Female
</label>
</div>
</div>
);
}
Form Validation:
function ValidatedForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [errors, setErrors] = useState({});
const validate = () => {
const newErrors = {};
if (!email) {
newErrors.email = 'Email is required';
} else if (!/\S+@\S+\.\S+/.test(email)) {
newErrors.email = 'Email is invalid';
}
if (!password) {
newErrors.password = 'Password is required';
} else if (password.length < 6) {
newErrors.password = 'Password must be at least 6 characters';
}
return newErrors;
};
const handleSubmit = (e) => {
e.preventDefault();
const validationErrors = validate();
if (Object.keys(validationErrors).length > 0) {
setErrors(validationErrors);
return;
}
// Submit form
console.log('Form is valid!', { email, password });
setErrors({});
};
return (
<form onSubmit={handleSubmit}>
<div>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
{errors.email && <span className="error">{errors.email}</span>}
</div>
<div>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
{errors.password && <span className="error">{errors.password}</span>}
</div>
<button type="submit">Submit</button>
</form>
);
}
Advanced Hooks
useContext: Global State Management
This ReactJS tutorial covers context for avoiding prop drilling.
Creating Context:
import { createContext, useContext, useState } from 'react';
// Create context
const ThemeContext = createContext();
// Provider component
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Custom hook for using theme
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
}
// Component using context
function ThemedButton() {
const { theme, toggleTheme } = useTheme();
return (
<button
onClick={toggleTheme}
style={{
background: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#333' : '#fff'
}}
>
Current theme: {theme}
</button>
);
}
// App
function App() {
return (
<ThemeProvider>
<ThemedButton />
</ThemeProvider>
);
}
User Authentication Example:
const AuthContext = createContext();
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Check if user is logged in
const token = localStorage.getItem('token');
if (token) {
// Validate token and get user
fetchUser(token).then(setUser);
}
setLoading(false);
}, []);
const login = async (email, password) => {
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ email, password })
});
const data = await response.json();
setUser(data.user);
localStorage.setItem('token', data.token);
};
const logout = () => {
setUser(null);
localStorage.removeItem('token');
};
return (
<AuthContext.Provider value={{ user, login, logout, loading }}>
{children}
</AuthContext.Provider>
);
}
function useAuth() {
return useContext(AuthContext);
}
// Using auth context
function UserProfile() {
const { user, logout } = useAuth();
return (
<div>
<h2>Welcome, {user.name}!</h2>
<button onClick={logout}>Logout</button>
</div>
);
}
useReducer: Complex State Logic
useReducer manages complex state in this ReactJS tutorial.
Basic useReducer:
import { useReducer } from 'react';
function reducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
case 'RESET':
return { count: 0 };
default:
throw new Error('Unknown action');
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button>
<button onClick={() => dispatch({ type: 'RESET' })}>Reset</button>
</div>
);
}
Todo App with useReducer:
const initialState = {
todos: [],
filter: 'all'
};
function todoReducer(state, action) {
switch (action.type) {
case 'ADD_TODO':
return {
...state,
todos: [...state.todos, {
id: Date.now(),
text: action.payload,
completed: false
}]
};
case 'TOGGLE_TODO':
return {
...state,
todos: state.todos.map(todo =>
todo.id === action.payload
? { ...todo, completed: !todo.completed }
: todo
)
};
case 'DELETE_TODO':
return {
...state,
todos: state.todos.filter(todo => todo.id !== action.payload)
};
case 'SET_FILTER':
return {
...state,
filter: action.payload
};
default:
return state;
}
}
function TodoApp() {
const [state, dispatch] = useReducer(todoReducer, initialState);
const [input, setInput] = useState('');
const addTodo = () => {
if (input.trim()) {
dispatch({ type: 'ADD_TODO', payload: input });
setInput('');
}
};
const filteredTodos = state.todos.filter(todo => {
if (state.filter === 'completed') return todo.completed;
if (state.filter === 'active') return !todo.completed;
return true;
});
return (
<div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && addTodo()}
/>
<button onClick={addTodo}>Add</button>
<div>
<button onClick={() => dispatch({ type: 'SET_FILTER', payload: 'all' })}>
All
</button>
<button onClick={() => dispatch({ type: 'SET_FILTER', payload: 'active' })}>
Active
</button>
<button onClick={() => dispatch({ type: 'SET_FILTER', payload: 'completed' })}>
Completed
</button>
</div>
<ul>
{filteredTodos.map(todo => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => dispatch({ type: 'TOGGLE_TODO', payload: todo.id })}
/>
<span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
{todo.text}
</span>
<button onClick={() => dispatch({ type: 'DELETE_TODO', payload: todo.id })}>
Delete
</button>
</li>
))}
</ul>
</div>
);
}
useRef: References and DOM Access
useRef is important in this ReactJS tutorial for accessing DOM and persisting values.
Accessing DOM Elements:
import { useRef, useEffect } from 'react';
function AutoFocusInput() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return <input ref={inputRef} />;
}
Storing Mutable Values:
function Timer() {
const [seconds, setSeconds] = useState(0);
const intervalRef = useRef(null);
const startTimer = () => {
intervalRef.current = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
};
const stopTimer = () => {
clearInterval(intervalRef.current);
};
useEffect(() => {
return () => clearInterval(intervalRef.current);
}, []);
return (
<div>
<p>Seconds: {seconds}</p>
<button onClick={startTimer}>Start</button>
<button onClick={stopTimer}>Stop</button>
</div>
);
}
Tracking Previous Values:
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
function Counter() {
const [count, setCount] = useState(0);
const prevCount = usePrevious(count);
return (
<div>
<p>Current: {count}</p>
<p>Previous: {prevCount}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
useMemo and useCallback: Performance Optimization
These hooks optimize performance in this ReactJS tutorial.
useMemo – Memoizing Values:
import { useMemo } from 'react';
function ExpensiveComponent({ numbers }) {
const sum = useMemo(() => {
console.log('Calculating sum...');
return numbers.reduce((acc, num) => acc + num, 0);
}, [numbers]);
return <div>Sum: {sum}</div>;
}
useCallback – Memoizing Functions:
import { useCallback } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
// Without useCallback, new function created every render
const handleClick = useCallback(() => {
console.log('Button clicked!');
}, []); // Empty deps - function never changes
return (
<div>
<input value={text} onChange={(e) => setText(e.target.value)} />
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<ChildComponent onClick={handleClick} />
</div>
);
}
const ChildComponent = React.memo(({ onClick }) => {
console.log('Child rendered');
return <button onClick={onClick}>Click Me</button>;
});
Practical Example:
function SearchComponent() {
const [query, setQuery] = useState('');
const [filter, setFilter] = useState('all');
const [data, setData] = useState([]);
// Expensive filtering operation
const filteredData = useMemo(() => {
console.log('Filtering data...');
return data
.filter(item => item.name.toLowerCase().includes(query.toLowerCase()))
.filter(item => filter === 'all' || item.category === filter);
}, [data, query, filter]);
// Memoized callback
const handleItemClick = useCallback((id) => {
console.log('Item clicked:', id);
}, []);
return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
/>
<select value={filter} onChange={(e) => setFilter(e.target.value)}>
<option value="all">All</option>
<option value="electronics">Electronics</option>
<option value="books">Books</option>
</select>
<ul>
{filteredData.map(item => (
<li key={item.id} onClick={() => handleItemClick(item.id)}>
{item.name}
</li>
))}
</ul>
</div>
);
}
Custom Hooks
Creating reusable logic with custom hooks—advanced topic in this ReactJS tutorial.
useLocalStorage Hook:
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
// Usage
function App() {
const [name, setName] = useLocalStorage('name', '');
return (
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
);
}
useFetch Hook:
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch(url)
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(error => {
setError(error);
setLoading(false);
});
}, [url]);
return { data, loading, error };
}
// Usage
function UserList() {
const { data, loading, error } = useFetch('https://api.example.com/users');
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
useToggle Hook:
function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = useCallback(() => {
setValue(prev => !prev);
}, []);
return [value, toggle];
}
// Usage
function ToggleComponent() {
const [isOn, toggle] = useToggle(false);
return (
<div>
<p>Status: {isOn ? 'ON' : 'OFF'}</p>
<button onClick={toggle}>Toggle</button>
</div>
);
}
useDebounce Hook:
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// Usage
function SearchInput() {
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearchTerm = useDebounce(searchTerm, 500);
useEffect(() => {
if (debouncedSearchTerm) {
// Perform search
console.log('Searching for:', debouncedSearchTerm);
}
}, [debouncedSearchTerm]);
return (
<input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search..."
/>
);
}
Building Real Projects
Project 1: Todo List Application
Let’s build a complete todo app in this ReactJS tutorial.
import { useState } from 'react';
import './TodoApp.css';
function TodoApp() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const [filter, setFilter] = useState('all');
const addTodo = () => {
if (input.trim()) {
setTodos([...todos, {
id: Date.now(),
text: input,
completed: false,
createdAt: new Date()
}]);
setInput('');
}
};
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));
};
const editTodo = (id, newText) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, text: newText } : todo
));
};
const clearCompleted = () => {
setTodos(todos.filter(todo => !todo.completed));
};
const filteredTodos = todos.filter(todo => {
if (filter === 'active') return !todo.completed;
if (filter === 'completed') return todo.completed;
return true;
});
const stats = {
total: todos.length,
active: todos.filter(t => !t.completed).length,
completed: todos.filter(t => t.completed).length
};
return (
<div className="todo-app">
<h1>My Todo List</h1>
<div className="todo-input">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && addTodo()}
placeholder="What needs to be done?"
/>
<button onClick={addTodo}>Add</button>
</div>
<div className="todo-filters">
<button
className={filter === 'all' ? 'active' : ''}
onClick={() => setFilter('all')}
>
All ({stats.total})
</button>
<button
className={filter === 'active' ? 'active' : ''}
onClick={() => setFilter('active')}
>
Active ({stats.active})
</button>
<button
className={filter === 'completed' ? 'active' : ''}
onClick={() => setFilter('completed')}
>
Completed ({stats.completed})
</button>
</div>
<ul className="todo-list">
{filteredTodos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={toggleTodo}
onDelete={deleteTodo}
onEdit={editTodo}
/>
))}
</ul>
{stats.completed > 0 && (
<button onClick={clearCompleted} className="clear-completed">
Clear Completed
</button>
)}
</div>
);
}
function TodoItem({ todo, onToggle, onDelete, onEdit }) {
const [isEditing, setIsEditing] = useState(false);
const [editText, setEditText] = useState(todo.text);
const handleEdit = () => {
if (editText.trim()) {
onEdit(todo.id, editText);
setIsEditing(false);
}
};
return (
<li className={`todo-item ${todo.completed ? 'completed' : ''}`}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => onToggle(todo.id)}
/>
{isEditing ? (
<input
value={editText}
onChange={(e) => setEditText(e.target.value)}
onBlur={handleEdit}
onKeyPress={(e) => e.key === 'Enter' && handleEdit()}
autoFocus
/>
) : (
<span onDoubleClick={() => setIsEditing(true)}>
{todo.text}
</span>
)}
<button onClick={() => onDelete(todo.id)}>Delete</button>
</li>
);
}
export default TodoApp;
Project 2: Weather App
A weather application demonstrating API integration in this ReactJS tutorial.
import { useState } from 'react';
function WeatherApp() {
const [city, setCity] = useState('');
const [weather, setWeather] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const API_KEY = 'your_api_key_here';
const fetchWeather = async () => {
if (!city.trim()) return;
setLoading(true);
setError(null);
try {
const response = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}&units=metric`
);
if (!response.ok) {
throw new Error('City not found');
}
const data = await response.json();
setWeather(data);
} catch (err) {
setError(err.message);
setWeather(null);
} finally {
setLoading(false);
}
};
const handleSubmit = (e) => {
e.preventDefault();
fetchWeather();
};
return (
<div className="weather-app">
<h1>Weather App</h1>
<form onSubmit={handleSubmit}>
<input
type="text"
value={city}
onChange={(e) => setCity(e.target.value)}
placeholder="Enter city name"
/>
<button type="submit">Get Weather</button>
</form>
{loading && <div className="loading">Loading...</div>}
{error && <div className="error">{error}</div>}
{weather && (
<div className="weather-card">
<h2>{weather.name}, {weather.sys.country}</h2>
<div className="temperature">
{Math.round(weather.main.temp)}°C
</div>
<div className="description">
{weather.weather[0].description}
</div>
<div className="details">
<div>Feels like: {Math.round(weather.main.feels_like)}°C</div>
<div>Humidity: {weather.main.humidity}%</div>
<div>Wind: {weather.wind.speed} m/s</div>
</div>
</div>
)}
</div>
);
}
export default WeatherApp;
Project 3: E-commerce Product List
A product listing with cart functionality in this ReactJS tutorial.
import { useState, createContext, useContext } from 'react';
// Context for cart
const CartContext = createContext();
function CartProvider({ children }) {
const [cart, setCart] = useState([]);
const addToCart = (product) => {
setCart(prev => {
const existing = prev.find(item => item.id === product.id);
if (existing) {
return prev.map(item =>
item.id === product.id
? { ...item, quantity: item.quantity + 1 }
: item
);
}
return [...prev, { ...product, quantity: 1 }];
});
};
const removeFromCart = (id) => {
setCart(prev => prev.filter(item => item.id !== id));
};
const updateQuantity = (id, quantity) => {
if (quantity === 0) {
removeFromCart(id);
return;
}
setCart(prev => prev.map(item =>
item.id === id ? { ...item, quantity } : item
));
};
const total = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
return (
<CartContext.Provider value={{ cart, addToCart, removeFromCart, updateQuantity, total }}>
{children}
</CartContext.Provider>
);
}
function useCart() {
return useContext(CartContext);
}
// Product Component
function ProductCard({ product }) {
const { addToCart } = useCart();
return (
<div className="product-card">
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<p className="price">${product.price.toFixed(2)}</p>
<p className="description">{product.description}</p>
<button onClick={() => addToCart(product)}>
Add to Cart
</button>
</div>
);
}
// Cart Component
function Cart() {
const { cart, removeFromCart, updateQuantity, total } = useCart();
if (cart.length === 0) {
return <div className="cart">Your cart is empty</div>;
}
return (
<div className="cart">
<h2>Shopping Cart</h2>
{cart.map(item => (
<div key={item.id} className="cart-item">
<img src={item.image} alt={item.name} />
<div className="cart-item-details">
<h3>{item.name}</h3>
<p>${item.price.toFixed(2)}</p>
</div>
<div className="cart-item-actions">
<button onClick={() => updateQuantity(item.id, item.quantity - 1)}>-</button>
<span>{item.quantity}</span>
<button onClick={() => updateQuantity(item.id, item.quantity + 1)}>+</button>
<button onClick={() => removeFromCart(item.id)}>Remove</button>
</div>
</div>
))}
<div className="cart-total">
<h3>Total: ${total.toFixed(2)}</h3>
<button className="checkout-btn">Checkout</button>
</div>
</div>
);
}
// Main App
function ShopApp() {
const [showCart, setShowCart] = useState(false);
const products = [
{ id: 1, name: 'Laptop', price: 999.99, image: '/laptop.jpg', description: 'Powerful laptop' },
{ id: 2, name: 'Phone', price: 699.99, image: '/phone.jpg', description: 'Latest smartphone' },
{ id: 3, name: 'Headphones', price: 199.99, image: '/headphones.jpg', description: 'Noise-cancelling' },
];
return (
<CartProvider>
<div className="shop-app