Learn React.js from scratch with this comprehensive beginner's guide. Covers components, state, props, hooks, and building your first React application step by step.
React.js has become the most popular JavaScript library for building user interfaces. Created by Facebook, it powers Instagram, WhatsApp Web, Netflix, and thousands of other applications.
If you're looking to enter front-end development or level up your JavaScript skills, learning React is one of the best investments you can make. This comprehensive tutorial takes you from zero to building real React applications.
React is a JavaScript library for building user interfaces, specifically for single-page applications. It allows you to create reusable UI components that update efficiently when data changes.
| Feature | React | Vue | Angular |
|---|---|---|---|
| Type | Library | Framework | Framework |
| Learning Curve | Medium | Easy | Steep |
| Size | Small (42kb) | Small (33kb) | Large (143kb) |
| Data Binding | One-way | Two-way | Two-way |
| Created By | Evan You | ||
| Popularity | Highest | High | High |
| Reason | Explanation |
|---|---|
| Job Market | Most in-demand front-end skill |
| Large Ecosystem | Huge community, many libraries |
| Component-Based | Reusable, maintainable code |
| React Native | Build mobile apps with same skills |
| Performance | Virtual DOM makes updates efficient |
| Industry Standard | Used by top companies globally |
Before starting React, you should know:
| Skill | Level Needed |
|---|---|
| HTML | Comfortable |
| CSS | Comfortable |
| JavaScript | Strong fundamentals |
JavaScript Concepts You Need:
| Concept | Why Important |
|---|---|
| Variables (let, const) | Used throughout |
| Arrow functions | Component syntax |
| Array methods (map, filter) | Rendering lists |
| Destructuring | Props and state |
| Spread operator | Updating state |
| Modules (import/export) | Organizing code |
| Template literals | JSX usage |
| Promises/async-await | API calls |
If these are unfamiliar, spend 1-2 weeks on modern JavaScript first.
Node.js (version 16+)
node --versionCode Editor
Browser
Using Create React App (CRA):
npx create-react-app my-first-app
cd my-first-app
npm start
Using Vite (Faster alternative):
npm create vite@latest my-app -- --template react
cd my-app
npm install
npm run dev
Your app runs at http://localhost:3000 (CRA) or http://localhost:5173 (Vite).
my-app/
├── node_modules/ # Dependencies
├── public/ # Static files
│ └── index.html # Main HTML file
├── src/ # Source code
│ ├── App.js # Main component
│ ├── App.css # Styles
│ ├── index.js # Entry point
│ └── index.css # Global styles
├── package.json # Project config
└── README.md
JSX (JavaScript XML) lets you write HTML-like code in JavaScript. It's not HTML—it's a syntax extension that gets compiled to JavaScript.
JSX:
const element = <h1>Hello, World!</h1>;
Compiles to:
const element = React.createElement('h1', null, 'Hello, World!');
| Rule | Example |
|---|---|
| Return single root element | Wrap in <div> or <> (Fragment) |
| Close all tags | <img /> not <img> |
Use className not class | <div className="box"> |
Use htmlFor not for | <label htmlFor="name"> |
| camelCase for attributes | onClick, onSubmit |
JavaScript in {} | <p>{variable}</p> |
Expressions in JSX:
const name = 'John';
const element = <h1>Hello, {name}!</h1>;
Conditional Rendering:
const isLoggedIn = true;
return <div>{isLoggedIn ? <p>Welcome back!</p> : <p>Please log in</p>}</div>;
Rendering Lists:
const items = ['Apple', 'Banana', 'Orange'];
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
Components are the building blocks of React applications. They are reusable, independent pieces of UI.
Types of Components:
| Type | Syntax | State Support |
|---|---|---|
| Function Component | Function | Yes (with hooks) |
| Class Component | ES6 Class | Yes (built-in) |
Modern React uses function components almost exclusively.
Basic Component:
function Welcome() {
return <h1>Hello, World!</h1>;
}
Arrow Function:
const Welcome = () => {
return <h1>Hello, World!</h1>;
};
Using the Component:
function App() {
return (
<div>
<Welcome />
<Welcome />
</div>
);
}
| Practice | Why |
|---|---|
| One component per file | Organization |
| PascalCase naming | React requirement |
| Start simple | Break down later |
| Keep components small | Easier to maintain |
| Single responsibility | One purpose per component |
Full Page:
function App() {
return (
<div>
<Header />
<MainContent />
<Footer />
</div>
);
}
Header Component:
function Header() {
return (
<header>
<Logo />
<Navigation />
</header>
);
}
Props (properties) are how you pass data from parent to child components. They're read-only—a component cannot modify its own props.
Parent Component:
function App() {
return (
<div>
<Greeting
name="John"
age={25}
/>
<Greeting
name="Jane"
age={30}
/>
</div>
);
}
Child Component:
function Greeting(props) {
return (
<p>
Hello, {props.name}! You are {props.age} years old.
</p>
);
}
Cleaner Syntax:
function Greeting({ name, age }) {
return (
<p>
Hello, {name}! You are {age} years old.
</p>
);
}
function Greeting({ name = 'Guest', age = 0 }) {
return (
<p>
Hello, {name}! You are {age} years old.
</p>
);
}
Special children prop for content inside component tags:
function Card({ children, title }) {
return (
<div className="card">
<h2>{title}</h2>
{children}
</div>
);
}
// Usage
<Card title="Welcome">
<p>This is the card content</p>
<button>Click me</button>
</Card>;
State is data that can change over time and affects what the component renders. When state changes, React re-renders the component.
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>
);
}
Breakdown:
useState(0): Initialize state with value 0count: Current state valuesetCount: Function to update stateWith New Value:
setCount(5); // Set to 5
With Previous Value (recommended for updates based on previous):
setCount((prevCount) => prevCount + 1);
function Form() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [age, setAge] = useState(0);
// ...
}
function Form() {
const [formData, setFormData] = useState({
name: '',
email: '',
age: 0,
});
const handleChange = (e) => {
setFormData({
...formData, // Keep existing values
[e.target.name]: e.target.value, // Update one field
});
};
return (
<input
name="name"
value={formData.name}
onChange={handleChange}
/>
);
}
function TodoList() {
const [todos, setTodos] = useState(['Learn React', 'Build a project']);
const addTodo = (newTodo) => {
setTodos([...todos, newTodo]); // Add to end
};
const removeTodo = (index) => {
setTodos(todos.filter((_, i) => i !== index)); // Remove by index
};
return (
<ul>
{todos.map((todo, index) => (
<li key={index}>
{todo}
<button onClick={() => removeTodo(index)}>Delete</button>
</li>
))}
</ul>
);
}
function Button() {
const handleClick = () => {
alert('Button clicked!');
};
return <button onClick={handleClick}>Click Me</button>;
}
Inline Handler (for simple cases):
<button onClick={() => alert('Clicked!')}>Click</button>
| Event | React Event | Use Case |
|---|---|---|
| Click | onClick | Buttons, links |
| Change | onChange | Inputs, selects |
| Submit | onSubmit | Forms |
| Focus | onFocus | Input focus |
| Blur | onBlur | Input loses focus |
| Mouse Over | onMouseOver | Hover effects |
| Key Press | onKeyDown | Keyboard shortcuts |
function ItemList() {
const handleDelete = (id) => {
console.log('Deleting item:', id);
};
return <button onClick={() => handleDelete(5)}>Delete Item 5</button>;
}
function LoginForm() {
const [formData, setFormData] = useState({
email: '',
password: '',
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prev) => ({
...prev,
[name]: value,
}));
};
const handleSubmit = (e) => {
e.preventDefault(); // Prevent page reload
console.log('Form submitted:', formData);
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
/>
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
placeholder="Password"
/>
<button type="submit">Login</button>
</form>
);
}
useEffect lets you perform side effects in function components:
import { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
// Runs after every render
document.title = `Count: ${count}`;
});
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
| Dependency | When Effect Runs |
|---|---|
| No array | After every render |
Empty array [] | Only on mount (once) |
With values [value] | When value changes |
Run Once on Mount:
useEffect(() => {
console.log('Component mounted');
}, []); // Empty array
Run When Value Changes:
useEffect(() => {
console.log('Count changed to:', count);
}, [count]); // Only when count changes
For effects that need cleanup (subscriptions, timers):
useEffect(() => {
const timer = setInterval(() => {
console.log('Tick');
}, 1000);
// Cleanup function
return () => {
clearInterval(timer);
};
}, []);
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchUser = async () => {
try {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
setUser(data);
} catch (error) {
console.error('Error fetching user:', error);
} finally {
setLoading(false);
}
};
fetchUser();
}, [userId]); // Re-fetch when userId changes
if (loading) return <p>Loading...</p>;
if (!user) return <p>User not found</p>;
return <div>{user.name}</div>;
}
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
}
return <h1>Please sign in</h1>;
}
function Greeting({ isLoggedIn }) {
return <div>{isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please sign in</h1>}</div>;
}
Render something only if condition is true:
function Notification({ hasMessages, count }) {
return <div>{hasMessages && <p>You have {count} new messages</p>}</div>;
}
function StatusMessage({ status }) {
return (
<div>
{status === 'loading' && <Spinner />}
{status === 'error' && <ErrorMessage />}
{status === 'success' && <SuccessMessage />}
</div>
);
}
function TodoList() {
const todos = [
{ id: 1, text: 'Learn React' },
{ id: 2, text: 'Build a project' },
{ id: 3, text: 'Deploy it' },
];
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}
Keys help React identify which items changed, were added, or removed:
Good Key:
{
todos.map((todo) => <li key={todo.id}>{todo.text}</li>);
}
Bad Key (avoid):
{
todos.map((todo, index) => (
<li key={index}>{todo.text}</li> // Problematic if list reorders
));
}
App.css:
.button {
background-color: blue;
color: white;
padding: 10px 20px;
}
Component:
import './App.css';
function Button() {
return <button className="button">Click Me</button>;
}
function Button() {
const buttonStyle = {
backgroundColor: 'blue',
color: 'white',
padding: '10px 20px',
border: 'none',
borderRadius: '5px',
};
return <button style={buttonStyle}>Click Me</button>;
}
Button.module.css:
.button {
background-color: blue;
color: white;
}
Component:
import styles from './Button.module.css';
function Button() {
return <button className={styles.button}>Click Me</button>;
}
import styled from 'styled-components';
const StyledButton = styled.button`
background-color: blue;
color: white;
padding: 10px 20px;
&:hover {
background-color: darkblue;
}
`;
function Button() {
return <StyledButton>Click Me</StyledButton>;
}
Let's build a complete todo application:
import { useState } from 'react';
import TodoForm from './components/TodoForm';
import TodoList from './components/TodoList';
import './App.css';
function App() {
const [todos, setTodos] = useState([]);
const addTodo = (text) => {
const newTodo = {
id: Date.now(),
text,
completed: false,
};
setTodos([...todos, newTodo]);
};
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="app">
<h1>Todo App</h1>
<TodoForm onAdd={addTodo} />
<TodoList
todos={todos}
onToggle={toggleTodo}
onDelete={deleteTodo}
/>
</div>
);
}
export default App;
import { useState } from 'react';
function TodoForm({ onAdd }) {
const [input, setInput] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (input.trim()) {
onAdd(input);
setInput('');
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Add a new todo..."
/>
<button type="submit">Add</button>
</form>
);
}
export default TodoForm;
import TodoItem from './TodoItem';
function TodoList({ todos, onToggle, onDelete }) {
if (todos.length === 0) {
return <p>No todos yet. Add one above!</p>;
}
return (
<ul className="todo-list">
{todos.map((todo) => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={onToggle}
onDelete={onDelete}
/>
))}
</ul>
);
}
export default TodoList;
function TodoItem({ todo, onToggle, onDelete }) {
return (
<li 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>
</li>
);
}
export default TodoItem;
| Topic | Why Important |
|---|---|
| React Router | Multi-page apps |
| Context API | Global state |
| Custom Hooks | Reusable logic |
| State Management (Redux/Zustand) | Complex state |
| React Query | Server state |
| TypeScript with React | Type safety |
| Testing (Jest, React Testing Library) | Quality assurance |
| Level | Project |
|---|---|
| Beginner | Todo App, Counter, Quiz App |
| Intermediate | Weather App, E-commerce Cart, Blog |
| Advanced | Social Media Clone, Dashboard, Full-stack App |
Basics: 2-4 weeks. Comfortable for projects: 2-3 months. Advanced: 6+ months of building projects.
Yes. Solid JavaScript fundamentals (especially ES6+) are essential. Spend 1-2 months on JavaScript before React.
React has the largest job market. Vue is easiest to learn. Angular is comprehensive but complex. For careers, React is usually the best choice.
Not for new projects. Modern React uses function components with hooks. Learn them briefly for reading legacy code.
Any backend works. Popular choices: Node.js/Express, Python/Django, or Firebase for quick setup.
Learning web development? Explore more resources on Sproutern for programming tutorials, career guidance, and skill development.
Our team of career experts, industry professionals, and former recruiters brings decades of combined experience in helping students and freshers launch successful careers.
Discover the best programming languages to learn for career growth and high-paying tech jobs....
Master Data Structures and Algorithms with this complete roadmap. From arrays to dynamic programming...
If you found this article helpful, please cite it as: