Complete React Tutorial for Beginners 2025: Master Modern Web Development with React.js
Introduction to React and Modern Web Development
React has revolutionized web development, becoming the most popular JavaScript library for building user interfaces. Created and maintained by Facebook (Meta), React powers countless websites and applications including Facebook, Instagram, Netflix, Airbnb, WhatsApp Web, and thousands of other major platforms. Learning React opens doors to high-paying frontend developer positions and enables you to build modern, interactive web applications that users love.
This comprehensive React tutorial guides you from fundamental concepts to advanced techniques, providing practical code examples you can implement immediately. Whether you're aspiring to become a frontend developer, full-stack engineer, or enhance your JavaScript skills, mastering React positions you at the forefront of modern web development with skills that employers actively seek and highly value.
What is React and Why Learn It?
React is a JavaScript library for building user interfaces, focusing specifically on creating reusable UI components that efficiently update when data changes. Unlike full frameworks like Angular or Vue, React concentrates on the view layer, giving developers flexibility to choose additional tools and libraries for routing, state management, and other functionality.
Career Opportunities: React developers rank among the highest-paid frontend professionals, with average salaries ranging from eighty thousand to one hundred forty thousand dollars annually in the United States. Senior React developers, technical leads, and specialists in React Native (mobile development) command even higher compensation. The demand for React skills continues growing as more companies adopt React for web and mobile applications.
React Advantages: The component-based architecture promotes code reusability, making applications easier to develop and maintain. React's virtual DOM efficiently updates only changed elements, delivering exceptional performance even in complex applications. The massive React ecosystem provides thousands of libraries, tools, and resources supporting virtually any development need. Strong community support ensures abundant learning resources, open-source components, and solutions to common challenges.
React Ecosystem: Beyond core React, developers commonly use React Router for navigation, Redux or Context API for state management, Next.js for server-side rendering and static site generation, React Native for mobile app development, Material-UI or Ant Design for component libraries, and countless specialized libraries for specific functionality.
Setting Up React Development Environment
Prerequisites
Before starting React development, ensure solid understanding of HTML, CSS, and JavaScript fundamentals including ES6+ features like arrow functions, destructuring, spread operators, template literals, and classes. Familiarity with JavaScript concepts like callbacks, promises, and async/await proves beneficial though not strictly required for beginning React.
Installing Node.js and npm
React development requires Node.js and npm (Node Package Manager). Visit nodejs.org and download the LTS (Long Term Support) version for your operating system. Installation includes both Node.js and npm automatically.
Verify Installation:
node --version
npm --version
These commands display installed versions, confirming successful installation.
Creating React Application with Create React App
Create React App provides the fastest way to start React projects, handling configuration automatically including webpack bundling, Babel transpilation, development server, and build optimization.
Create New React App:
npx create-react-app my-first-app
cd my-first-app
npm start
This creates new React project, navigates into directory, and starts development server. Your browser automatically opens showing the default React welcome page at localhost:3000.
Project Structure:
my-first-app/
├── node_modules/
├── public/
│ ├── index.html
│ └── favicon.ico
├── src/
│ ├── App.js
│ ├── App.css
│ ├── index.js
│ └── index.css
├── package.json
└── README.md
The src folder contains your application code. The public folder holds static files. The node_modules folder contains all dependencies.
Development Environment Setup
Visual Studio Code: Download from code.visualstudio.com for the most popular React development editor. Install helpful extensions including ES7+ React/Redux/React-Native snippets for code shortcuts, Prettier for code formatting, ESLint for code quality checking, and Auto Import for automatic import statements.
React Fundamentals: JSX and Components
Understanding JSX
JSX (JavaScript XML) allows writing HTML-like syntax directly in JavaScript. This syntax extension makes React code more readable and intuitive.
// JSX example
const element = <h1>Hello, React!</h1>;
// Equivalent JavaScript
const element = React.createElement('h1', null, 'Hello, React!');
JSX Rules:
- Must return single parent element
- Use className instead of class (class is JavaScript keyword)
- Use camelCase for attributes (onClick instead of onclick)
- Close all tags including self-closing tags
- JavaScript expressions go inside curly braces
JSX Examples:
// JavaScript expressions in JSX
const name = "Alice";
const greeting = <h1>Hello, {name}!</h1>;
// Attributes with variables
const imageUrl = "photo.jpg";
const image = <img src={imageUrl} alt="Description" />;
// Conditional rendering
const isLoggedIn = true;
const message = <p>{isLoggedIn ? "Welcome back!" : "Please log in"}</p>;
// Styling with objects
const styles = { color: 'blue', fontSize: '20px' };
const styledText = <p style={styles}>Styled text</p>;
Functional Components
Components represent reusable pieces of UI. Modern React primarily uses functional components with hooks.
Basic Functional Component:
function Welcome() {
return <h1>Welcome to React!</h1>;
}
// Arrow function syntax
const Welcome = () => {
return <h1>Welcome to React!</h1>;
};
// Implicit return for simple components
const Welcome = () => <h1>Welcome to React!</h1>;
Component with Props:
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
// Destructuring props
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
// Using the component
<Greeting name="Alice" />
<Greeting name="Bob" />
Complete Component Example:
function UserCard({ name, email, age }) {
return (
<div className="user-card">
<h2>{name}</h2>
<p>Email: {email}</p>
<p>Age: {age}</p>
</div>
);
}
// Using the component
function App() {
return (
<div>
<UserCard name="John Doe" email="john@example.com" age={30} />
<UserCard name="Jane Smith" email="jane@example.com" age={28} />
</div>
);
}
React Hooks: useState
Hooks allow functional components to use state and lifecycle features previously available only in class components.
useState Hook Basics
useState adds state management to functional components.
import React, { useState } from 'react';
function Counter() {
// Declare state variable
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
<button onClick={() => setCount(count - 1)}>
Decrement
</button>
<button onClick={() => setCount(0)}>
Reset
</button>
</div>
);
}
useState Explanation:
useState(0)initializes state with value 0- Returns array with current state and setter function
countholds current state valuesetCountupdates state value- Component re-renders when state changes
Multiple State Variables
Components can use multiple useState hooks for different state values.
function UserForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [age, setAge] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log({ name, email, age });
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
/>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="number"
value={age}
onChange={(e) => setAge(e.target.value)}
placeholder="Age"
/>
<button type="submit">Submit</button>
</form>
);
}
State with Objects and Arrays
State can hold complex data structures.
// State with object
function UserProfile() {
const [user, setUser] = useState({
name: 'John',
age: 30,
email: 'john@example.com'
});
const updateName = () => {
setUser({ ...user, name: 'Jane' });
};
return (
<div>
<p>Name: {user.name}</p>
<button onClick={updateName}>Update Name</button>
</div>
);
}
// State with array
function TodoList() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const addTodo = () => {
setTodos([...todos, input]);
setInput('');
};
const removeTodo = (index) => {
setTodos(todos.filter((_, i) => i !== index));
};
return (
<div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Enter todo"
/>
<button onClick={addTodo}>Add Todo</button>
<ul>
{todos.map((todo, index) => (
<li key={index}>
{todo}
<button onClick={() => removeTodo(index)}>
Delete
</button>
</li>
))}
</ul>
</div>
);
}
Event Handling in React
React handles events similarly to HTML but with camelCase syntax and function references instead of strings.
function EventExamples() {
const handleClick = () => {
alert('Button clicked!');
};
const handleChange = (e) => {
console.log('Input value:', e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form submitted');
};
return (
<div>
{/* Click event */}
<button onClick={handleClick}>Click Me</button>
{/* Change event */}
<input onChange={handleChange} />
{/* Submit event */}
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
{/* Inline function */}
<button onClick={() => console.log('Inline click')}>
Inline Handler
</button>
{/* Event with parameters */}
<button onClick={() => handleClick('parameter')}>
With Parameter
</button>
</div>
);
}
Conditional Rendering
React provides multiple ways to conditionally render components or elements.
function ConditionalExamples({ isLoggedIn, userType, hasPermission }) {
// Using if-else
if (!isLoggedIn) {
return <LoginPage />;
}
return (
<div>
{/* Ternary operator */}
{isLoggedIn ? <Dashboard /> : <LoginPrompt />}
{/* Logical AND */}
{hasPermission && <AdminPanel />}
{/* Multiple conditions */}
{userType === 'admin' ? (
<AdminDashboard />
) : userType === 'user' ? (
<UserDashboard />
) : (
<GuestView />
)}
{/* Conditional className */}
<button className={isLoggedIn ? 'active' : 'inactive'}>
Status
</button>
</div>
);
}
Lists and Keys
Rendering lists requires unique keys helping React identify changed items.
function UserList() {
const users = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
{ id: 3, name: 'Charlie', age: 35 }
];
return (
<div>
<h2>User List</h2>
<ul>
{users.map(user => (
<li key={user.id}>
{user.name} - {user.age} years old
</li>
))}
</ul>
</div>
);
}
// More complex list rendering
function ProductList({ products }) {
return (
<div className="product-grid">
{products.map(product => (
<div key={product.id} className="product-card">
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<p>${product.price}</p>
<button>Add to Cart</button>
</div>
))}
</div>
);
}
useEffect Hook
useEffect handles side effects like data fetching, subscriptions, and DOM manipulation.
import React, { useState, useEffect } from 'react';
// Basic useEffect
function ExampleComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
});
return (
<button onClick={() => setCount(count + 1)}>
Click count: {count}
</button>
);
}
// useEffect with dependency array
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
});
}, []); // Empty array means run once on mount
if (loading) return <p>Loading...</p>;
return <div>{/* Display data */}</div>;
}
// useEffect with cleanup
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
// Cleanup function
return () => clearInterval(interval);
}, []);
return <p>Seconds: {seconds}</p>;
}
Component Communication: Props
Props (properties) pass data from parent to child components.
// Parent component
function ParentComponent() {
const userInfo = {
name: 'John Doe',
email: 'john@example.com',
age: 30
};
const handleClick = () => {
console.log('Button clicked in child');
};
return (
<div>
<ChildComponent
user={userInfo}
onButtonClick={handleClick}
/>
</div>
);
}
// Child component
function ChildComponent({ user, onButtonClick }) {
return (
<div>
<h2>{user.name}</h2>
<p>Email: {user.email}</p>
<p>Age: {user.age}</p>
<button onClick={onButtonClick}>
Click Me
</button>
</div>
);
}
// Children prop
function Card({ children, title }) {
return (
<div className="card">
<h3>{title}</h3>
<div className="card-body">
{children}
</div>
</div>
);
}
// Using Card component
<Card title="User Profile">
<p>Name: John Doe</p>
<p>Email: john@example.com</p>
</Card>
Forms in React
React handles forms using controlled components where form data is controlled by React state.
function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
subscribe: false,
category: 'general'
});
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);
// Send data to server
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Your Name"
required
/>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Your Email"
required
/>
<textarea
name="message"
value={formData.message}
onChange={handleChange}
placeholder="Your Message"
rows="5"
/>
<select
name="category"
value={formData.category}
onChange={handleChange}
>
<option value="general">General</option>
<option value="support">Support</option>
<option value="sales">Sales</option>
</select>
<label>
<input
type="checkbox"
name="subscribe"
checked={formData.subscribe}
onChange={handleChange}
/>
Subscribe to newsletter
</label>
<button type="submit">Submit</button>
</form>
);
}
React Router for Navigation
React Router enables navigation between different components without page reloads.
Installation:
npm install react-router-dom
Basic Routing:
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/contact">Contact</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="/users/:id" element={<UserProfile />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
// Component with URL parameters
import { useParams } from 'react-router-dom';
function UserProfile() {
const { id } = useParams();
return <h2>User Profile: {id}</h2>;
}
// Programmatic navigation
import { useNavigate } from 'react-router-dom';
function LoginForm() {
const navigate = useNavigate();
const handleLogin = () => {
// After successful login
navigate('/dashboard');
};
return <button onClick={handleLogin}>Login</button>;
}
Styling React Components
React supports multiple styling approaches.
// Inline styles
const Button = () => {
const buttonStyle = {
backgroundColor: 'blue',
color: 'white',
padding: '10px 20px',
border: 'none',
borderRadius: '5px'
};
return <button style={buttonStyle}>Click Me</button>;
};
// CSS Modules
import styles from './Button.module.css';
const Button = () => {
return <button className={styles.button}>Click Me</button>;
};
// Styled Components (requires installation)
import styled from 'styled-components';
const StyledButton = styled.button`
background-color: blue;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
&:hover {
background-color: darkblue;
}
`;
// Using Tailwind CSS
const Button = () => {
return (
<button className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
Click Me
</button>
);
};
Practical React Project: Todo Application
Complete working todo application demonstrating React concepts.
import React, { useState, useEffect } from 'react';
import './TodoApp.css';
function TodoApp() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const [filter, setFilter] = useState('all');
// Load todos from localStorage
useEffect(() => {
const savedTodos = localStorage.getItem('todos');
if (savedTodos) {
setTodos(JSON.parse(savedTodos));
}
}, []);
// Save todos to localStorage
useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos));
}, [todos]);
const addTodo = () => {
if (input.trim()) {
setTodos([
...todos,
{
id: Date.now(),
text: input,
completed: false
}
]);
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 filteredTodos = todos.filter(todo => {
if (filter === 'active') return !todo.completed;
if (filter === 'completed') return todo.completed;
return true;
});
return (
<div className="todo-app">
<h1>My Todo List</h1>
<div className="input-section">
<input
type="text"
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="filter-section">
<button onClick={() => setFilter('all')}>All</button>
<button onClick={() => setFilter('active')}>Active</button>
<button onClick={() => setFilter('completed')}>
Completed
</button>
</div>
<ul className="todo-list">
{filteredTodos.map(todo => (
<li key={todo.id} className={todo.completed ? 'completed' : ''}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
<span>{todo.text}</span>
<button onClick={() => deleteTodo(todo.id)}>
Delete
</button>
</li>
))}
</ul>
<div className="stats">
{todos.filter(t => !t.completed).length} items left
</div>
</div>
);
}
export default TodoApp;
React Best Practices
Component Organization: Keep components small and focused on single responsibility, extract reusable logic into custom hooks, organize files by feature rather than type, and use meaningful component and variable names.
State Management: Keep state as local as possible, lift state up only when necessary, use context for global state, and consider Redux for complex state needs.
Performance: Use React.memo for expensive components, implement useMemo and useCallback for optimization, avoid inline function creation in render, and lazy load components with React.lazy.
Code Quality: Use PropTypes or TypeScript for type checking, write tests for components, follow consistent naming conventions, and keep functions pure when possible.
Conclusion and Next Steps
You've learned React fundamentals including JSX, components, hooks, state management, event handling, routing, and styling. These concepts form the foundation for building modern web applications with React.
Continue Learning: Explore advanced hooks like useReducer, useCallback, useMemo, study Context API for state management, learn Redux for complex applications, master Next.js for server-side rendering, practice React Native for mobile apps, and build real projects solidifying your skills.
React development offers exciting career opportunities and enables building powerful user interfaces. Start creating projects, contribute to open-source, and continuously refine your React expertise. The React ecosystem continues evolving, making continuous learning essential for staying current with best practices and new features.