React is the “R” in MERN and the technology that controls everything the user sees and interacts with in the browser. It is a JavaScript library for building user interfaces, maintained by Meta (Facebook) and open-source contributors. React’s defining idea is simple but powerful: describe what the UI should look like for a given application state, and let React figure out the minimum set of DOM changes needed to make the browser match that description. This declarative approach โ combined with a component model that makes UI pieces reusable โ is what makes React so productive for building the kind of dynamic, data-driven interfaces that MERN applications require.
React in the MERN Stack
| Layer | Technology | Responsibility |
|---|---|---|
| Database | MongoDB | Stores application data as documents |
| API Server | Express + Node.js | Handles HTTP requests, queries MongoDB, returns JSON |
| UI Library | React | Renders the interface, manages UI state, calls the API |
npm create vite@latest client -- --template react/api/posts, displays it, and sends changes back to /api/posts โ never touching the database directly.How React Works โ The Mental Model
Traditional (Imperative) UI โ jQuery / vanilla JS:
1. User clicks "Load Posts"
2. You write code: find the list element, clear it, fetch data,
create new elements, append them one by one
3. You manually manage every DOM change
React (Declarative) UI:
1. You describe: "When posts = [...], render a <ul> with one <li> per post"
2. User clicks "Load Posts" โ state changes to posts = [{ title: '...' }, ...]
3. React automatically re-renders and updates only the changed DOM nodes
4. You never touch the DOM directly โ React handles it
The Virtual DOM
How React updates the UI efficiently:
Step 1: State changes (e.g. posts array updated with new data)
โ
โผ
Step 2: React re-renders the component in memory
(creates a new Virtual DOM โ a lightweight JS object tree)
โ
โผ
Step 3: React "diffs" the new Virtual DOM against the previous one
(finds the exact minimum set of changes needed)
โ
โผ
Step 4: React applies ONLY those changes to the real browser DOM
(e.g. adds 3 new <li> elements โ does not rebuild the whole list)
โ
โผ
Step 5: Browser paints the changes โ user sees the updated UI
Result: Fast, predictable updates even in complex, large UIs
Component-Based Architecture
Every piece of a React UI is a component โ a JavaScript function that accepts data (props) and returns JSX describing what to render. Components are composable: you build complex interfaces by nesting simpler components.
// A simple React component โ a function that returns JSX
function PostCard({ title, author, createdAt }) {
return (
<div className="post-card">
<h2>{title}</h2>
<p>By {author} ยท {new Date(createdAt).toLocaleDateString()}</p>
</div>
);
}
// Composing components โ PostList uses PostCard
function PostList({ posts }) {
return (
<ul className="post-list">
{posts.map(post => (
<PostCard
key={post._id}
title={post.title}
author={post.author.name}
createdAt={post.createdAt}
/>
))}
</ul>
);
}
React vs Other Frontend Approaches
| Approach | Key Characteristic | Learning Curve | Best For |
|---|---|---|---|
| Vanilla JS / jQuery | Imperative DOM manipulation | Low | Simple pages, minimal interactivity |
| React | Declarative, component-based, huge ecosystem | Medium | SPAs, dynamic data-driven UIs, MERN |
| Angular | Full framework โ routing, HTTP, DI built in | High | Large enterprise apps, MEAN stack |
| Vue | Progressive, gentle learning curve | Low-Medium | Teams transitioning from jQuery, MEVN |
| Svelte | Compiles away at build time โ no runtime | Low-Medium | Performance-critical, smaller bundles |
React’s Data Flow
// React data flows DOWN through props, events flow UP through callbacks
// Parent component โ owns the state and the data
function BlogPage() {
const [posts, setPosts] = React.useState([]);
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
// Fetch posts from the Express API
fetch('/api/posts')
.then(res => res.json())
.then(data => { setPosts(data.data); setLoading(false); });
}, []);
const handleDelete = (postId) => {
// Update local state after deletion โ no page reload
setPosts(prev => prev.filter(p => p._id !== postId));
};
if (loading) return <p>Loading...</p>;
return (
<div>
<h1>Blog</h1>
{posts.map(post => (
// Data flows DOWN as props
// Events flow UP as callbacks (onDelete)
<PostCard key={post._id} post={post} onDelete={handleDelete} />
))}
</div>
);
}
Common Mistakes
Mistake 1 โ Treating React like jQuery (imperative DOM manipulation)
โ Wrong โ manually touching the DOM inside React components:
function Counter() {
const handleClick = () => {
document.getElementById('count').textContent = '1'; // direct DOM manipulation
};
return <div><span id="count">0</span><button onClick={handleClick}>+</button></div>;
}
โ Correct โ use state to describe the desired UI and let React update the DOM:
function Counter() {
const [count, setCount] = React.useState(0);
return <div><span>{count}</span><button onClick={() => setCount(c => c + 1)}>+</button></div>;
}
Mistake 2 โ Confusing React with Next.js or Remix
โ Wrong โ expecting React to provide server-side rendering, file-based routing, or API routes out of the box.
โ Correct โ plain React (via Vite) produces a client-side single-page application. Next.js and Remix are React-based frameworks that add SSR, routing, and server features on top. For this MERN series, plain Vite + React is the right choice โ the Express API handles the server side.
Mistake 3 โ Calling the API directly from every component
โ Wrong โ scattered API calls across many components:
// PostCard.jsx โ makes its own API call
function PostCard({ postId }) {
useEffect(() => { fetch(`/api/posts/${postId}`).then(...) }, [postId]);
}
โ Correct โ centralise API calls in a service layer or a parent component and pass data down as props. Keep components focused on rendering, not data fetching.
Quick Reference
| Concept | Key Point |
|---|---|
| Component | A function that returns JSX |
| Props | Data passed into a component from its parent |
| State | Data owned and managed by a component โ changes trigger re-render |
| Virtual DOM | In-memory representation โ React diffs it to minimise real DOM updates |
| Declarative | Describe what the UI should look like โ not how to update it step by step |
| Unidirectional flow | Data flows down via props, events flow up via callback functions |