What Is React and Why Learn It?
React is a JavaScript library created by Meta (formerly Facebook) in 2013. Unlike frameworks like Angular or Vue, React is focused specifically on building UI components — it handles the "View" layer of your application. For routing, state management, and server communication, you combine React with other libraries.
Why React dominates frontend development:
- Component model: Break your UI into independent, reusable pieces
- Declarative: Describe what the UI should look like, not how to update it
- Large ecosystem: Thousands of compatible libraries for every need
- Job market: React skills are in higher demand than any other frontend framework
- React Native: Share knowledge with iOS and Android mobile development
Setting Up Your First React Project
The easiest way to start is with Vite (modern, fast) or Create React App (older, more familiar):
# Using Vite (recommended)
npm create vite@latest my-first-app -- --template react
cd my-first-app
npm install
npm run dev
# Using Create React App
npx create-react-app my-first-app
cd my-first-app
npm start
Visit http://localhost:5173 (Vite) or http://localhost:3000 (CRA) to see your app.
Understanding JSX
When you open src/App.jsx, you'll see what looks like HTML mixed with JavaScript. This is JSX (JavaScript XML):
function App() {
const name = "World";
const isLoggedIn = true;
return (
<div className="app">
<h1>Hello, {name}!</h1>
{isLoggedIn ? <p>Welcome back.</p> : <p>Please sign in.</p>}
</div>
);
}
export default App;
JSX is transformed into JavaScript by Babel. <h1>Hello, {name}!</h1> becomes React.createElement('h1', null, 'Hello, ', name) under the hood. The curly braces {} are escape hatches into JavaScript — you can put any JavaScript expression inside them.
JSX rules:
- Return a single root element (or use <>...</> fragment syntax)
- Close all tags — self-closing tags like <img /> require the slash
- Use className instead of class (class is a reserved word in JavaScript)
- Use camelCase for HTML attributes: onclick → onClick, tabindex → tabIndex
Your First Component
Components are the building blocks of React. A component is a JavaScript function that returns JSX:
// A simple button component
function Button({ label, onClick, variant = 'primary' }) {
return (
<button
className={`btn btn-${variant}`}
onClick={onClick}
>
{label}
</button>
);
}
// Using the component
function App() {
const handleClick = () => alert('Button clicked!');
return (
<div>
<Button label="Click Me" onClick={handleClick} />
<Button label="Cancel" onClick={() => {}} variant="secondary" />
</div>
);
}
Components must start with a capital letter — React uses this to distinguish between HTML elements (<div>) and custom components (<Button>).
Props: Passing Data to Components
Props (properties) are how parent components pass data to child components. They flow one direction: from parent to child:
// Parent passes props to child
function UserProfile() {
const user = {
name: "Alice Johnson",
role: "Software Engineer",
avatar: "https://example.com/alice.jpg",
joinDate: "2022",
};
return (
<ProfileCard
name={user.name}
role={user.role}
avatar={user.avatar}
joinDate={user.joinDate}
/>
);
}
// Child receives props as an object
function ProfileCard({ name, role, avatar, joinDate }) {
return (
<div className="profile-card">
<img src={avatar} alt={name} />
<h2>{name}</h2>
<p>{role}</p>
<small>Member since {joinDate}</small>
</div>
);
}
Props are read-only — components should never modify their props. If you need to change data, you use state (explained next).
State: Making Components Interactive
State is data that can change over time, causing the component to re-render:
import { useState } from 'react';
function Counter() {
// useState returns [currentValue, setterFunction]
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
Every time setCount is called, React:
- Updates the state value
- Re-renders the component with the new state
- Updates the DOM efficiently (only changed parts)
State rules:
- Never modify state directly: count++ won't trigger a re-render. Always use the setter.
- State updates may be batched — if you need the previous value, use the functional form:
// Safe — uses previous state value
setCount(prevCount => prevCount + 1);
// Unsafe — may use stale value in concurrent mode
setCount(count + 1);
Handling Lists
When rendering arrays, React needs a key prop on each item for efficient updates:
const fruits = ['Apple', 'Banana', 'Cherry', 'Dragonfruit'];
function FruitList() {
return (
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
);
}
// Better: use a unique ID as key (not index if the list can reorder)
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id} style={{ textDecoration: todo.done ? 'line-through' : 'none' }}>
{todo.text}
</li>
))}
</ul>
);
}
Handling Events and Forms
import { useState } from 'react';
function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
});
// Single handler for all inputs
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
const handleSubmit = (e) => {
e.preventDefault(); // Prevent page reload
console.log('Form data:', formData);
// Send to API...
};
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="Email address"
required
/>
<textarea
name="message"
value={formData.message}
onChange={handleChange}
rows={4}
placeholder="Your message"
/>
<button type="submit">Send Message</button>
</form>
);
}
The useEffect Hook: Side Effects
useEffect lets you perform side effects (data fetching, subscriptions, DOM manipulation) after rendering:
import { useState, useEffect } from 'react';
function WeatherWidget({ city }) {
const [weather, setWeather] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// This runs after the component renders (and when city changes)
fetch(`https://api.weather.example.com/current?city=${city}`)
.then(res => res.json())
.then(data => {
setWeather(data);
setLoading(false);
});
}, [city]); // Dependency array — re-run when city changes
if (loading) return <div>Loading weather...</div>;
return (
<div>
<h3>{city}</h3>
<p>{weather.temperature}°C — {weather.description}</p>
</div>
);
}
Component Composition
Build complex UIs by composing simple components:
function App() {
return (
<PageLayout>
<Header />
<main>
<HeroSection />
<FeaturesSection />
<TestimonialsSection />
</main>
<Footer />
</PageLayout>
);
}
This is the core philosophy of React: small, focused components that combine to form larger ones. Each component has a single responsibility and can be developed, tested, and reused independently.
What to Learn Next
After mastering these basics:
- React Router — client-side navigation
- useContext — sharing state without prop drilling
- useReducer — complex state management
- Custom hooks — extracting reusable logic
- Data fetching (React Query or SWR)
- Next.js — production-ready React framework