Kazi Rahamatullah
Kazi Rahamatullah
AboutProjectsBlogContact
UsesBooks
ResumeView CV
Kazi Rahamatullah

© Copyright 2026 Kazi Rahamatullah

AboutProjectsBlogBooksUses
Twitter/XGitHubProduct HuntCodeSandbox
Back to Blog
MERNReactHooksReact RouterZustandTesting

MERN Course: React Essentials

Weeks 10–13 of the MERN syllabus — components, hooks, routing, API fetching, Context, Zustand, testing with RTL, and capstone project guidance.

Jul 8, 20268 min read

Introduction

React is the front-end pillar of MERN. This post completes the React Essentials syllabus with production patterns — including the same MDX blog system this site uses.

Course Reference

Quick index

#TopicDescription
1Getting Started with ReactReact builds UIs from composable components.
2Components, Props, and StateProps flow down; state is local unless lifted or stored globally.
3Lists, Conditional Rendering & useEffectLists need stable key props (prefer IDs over array index).
4Event Handling and FormsControlled inputs bind value to state and onChange to update it.
5Styling React ComponentsOptions: CSS Modules (scoped classes), Tailwind utilities, CSS-in-JS (styled-components).
6React Router & Protected RoutesSPAs swap views without full page reloads.
7Fetching Data from APIsShow loading and error UI for every async request.
8Advanced Hooks & Context APIuseReducer for complex state, useContext to avoid prop drilling, useMemo/useCallback to stabilize references for memoized children..
9Redux & ZustandGlobal state stores shared data: cart, auth user, UI flags.
10Testing React ComponentsReact Testing Library queries how users interact (roles, labels).
11Final React ProjectCapstone: plan scope, pick state strategy (local → Context → Zustand), integrate an API, add tests for critical paths, deploy to Vercel..

Week 10: React Fundamentals

1. Getting Started with React

React builds UIs from composable components. JSX is syntax sugar for React.createElement. In 2026, use Vite or Next.js instead of deprecated Create React App for new projects.

Example:

jsx
function Welcome({ name }) {
  return <h1>Hello, {name}</h1>
}
 
export default function App() {
  return (
    <main>
      <Welcome name="MERN Developer" />
    </main>
  )
}

Note

Component names must start with uppercase. Lowercase tags are treated as HTML elements.

Tip

Apply this in your Week 10 course project before moving on.

Performance

Split large pages into smaller components — React re-renders the subtree when state changes.

Back to index


2. Components, Props, and State

Props flow down; state is local unless lifted or stored globally. useState returns current value and updater — updater can accept a function for prev state.

Example:

jsx
'use client'
import { useState } from 'react'
 
export function Counter({ step = 1 }) {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount((c) => c + step)}>Count: {count}</button>
}

Note

Never mutate state directly: count++ will not trigger re-render. Always use the setter.

Tip

Apply this in your Week 10 course project before moving on.

Performance

Lift state only as high as needed. State too high causes unnecessary re-renders in unrelated branches.

Back to index


3. Lists, Conditional Rendering & useEffect

Lists need stable key props (prefer IDs over array index). useEffect runs after paint — ideal for fetch, subscriptions, and syncing with localStorage.

Example:

jsx
useEffect(() => {
  const saved = localStorage.getItem('tasks')
  if (saved) setTasks(JSON.parse(saved))
}, [])
 
useEffect(() => {
  localStorage.setItem('tasks', JSON.stringify(tasks))
}, [tasks])

Note

Include all reactive values in the dependency array. Missing deps cause stale closures — ESLint react-hooks/exhaustive-deps helps.

Tip

Apply this in your Week 10 course project before moving on.

Performance

Avoid fetch in render. Use useEffect, React Query, or server components (Next.js) for data loading.

Back to index

Week 11: Events, Forms, Styling & Routing

4. Event Handling and Forms

Controlled inputs bind value to state and onChange to update it. Validation runs on blur, submit, or debounced input.

Example:

jsx
const [email, setEmail] = useState('')
const [error, setError] = useState('')
 
function handleSubmit(e) {
  e.preventDefault()
  if (!email.includes('@')) {
    setError('Invalid email')
    return
  }
  submitForm({ email })
}

Note

Use type="button" for non-submit buttons inside forms — default type is submit.

Tip

Apply this in your Week 11 course project before moving on.

Performance

Debounce search inputs. Uncontrolled inputs + ref can reduce re-renders for large forms — tradeoff is complexity.

Back to index


5. Styling React Components

Options: CSS Modules (scoped classes), Tailwind utilities, CSS-in-JS (styled-components). This portfolio uses Tailwind + CSS modules for demos.

Example:

jsx
import styles from './Card.module.css'
 
export function Card({ title, children }) {
  return (
    <article className={styles.card}>
      <h2>{title}</h2>
      {children}
    </article>
  )
}

Note

Avoid inline style objects recreated every render when passed to memoized children — they break referential equality.

Tip

Apply this in your Week 11 course project before moving on.

Performance

Tailwind JIT and CSS Modules both tree-shake unused styles. Prefer one system per project for consistency.

Back to index


6. React Router & Protected Routes

SPAs swap views without full page reloads. Protect routes by checking auth state and redirecting to login.

Example:

jsx
import { Navigate, Route, Routes } from 'react-router-dom'
 
function ProtectedRoute({ user, children }) {
  if (!user) return <Navigate to="/login" replace />
  return children
}

Note

In Next.js App Router, use middleware + server session checks instead of client-only route guards for real security.

Tip

Apply this in your Week 11 course project before moving on.

Performance

Lazy-load route components with React.lazy + Suspense to reduce initial bundle size.

Back to index

Week 12: APIs, Hooks & State Management

7. Fetching Data from APIs

Show loading and error UI for every async request. Abort in-flight fetches when component unmounts or deps change.

Example:

jsx
useEffect(() => {
  const controller = new AbortController()
  setLoading(true)
  fetch('/api/posts', { signal: controller.signal })
    .then((r) => r.json())
    .then(setPosts)
    .catch((err) => {
      if (err.name !== 'AbortError') setError(err.message)
    })
    .finally(() => setLoading(false))
  return () => controller.abort()
}, [])

Note

Prefer TanStack Query or SWR over manual useEffect fetch — caching and deduplication are built in.

Tip

Apply this in your Week 12 course project before moving on.

Performance

Dedupe identical in-flight requests. React Query does this automatically with the same query key.

Back to index


8. Advanced Hooks & Context API

useReducer for complex state, useContext to avoid prop drilling, useMemo/useCallback to stabilize references for memoized children.

Tip

Apply this in your Week 12 course project before moving on.

Back to index


9. Redux & Zustand

Global state stores shared data: cart, auth user, UI flags. Redux is verbose but predictable; Zustand is minimal and hook-friendly.

Example:

javascript
import { create } from 'zustand'
 
const useTaskStore = create((set) => ({
  tasks: [],
  addTask: (title) =>
    set((state) => ({
      tasks: [...state.tasks, { id: crypto.randomUUID(), title, done: false }],
    })),
}))

Note

Not every app needs Redux. Start with useState + Context; add Zustand when prop drilling hurts.

Tip

Apply this in your Week 12 course project before moving on.

Performance

Select slice of state in Zustand: useStore(s => s.tasks) — avoids re-render on unrelated store changes.

Back to index


Week 13: Testing & Final Project

10. Testing React Components

React Testing Library queries how users interact (roles, labels). Test visible behavior, not internal state.

Example:

javascript
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Counter } from './Counter'
 
test('increments on click', async () => {
  render(<Counter />)
  await userEvent.click(screen.getByRole('button'))
  expect(screen.getByText(/count: 1/i)).toBeInTheDocument()
})

Note

Use getByRole over getByTestId — closer to accessibility and user behavior.

Tip

Apply this in your Week 13 course project before moving on.

Performance

Mock network in tests with MSW. Real fetch calls slow suites and flake on network conditions.

Back to index


11. Final React Project

Capstone: plan scope, pick state strategy (local → Context → Zustand), integrate an API, add tests for critical paths, deploy to Vercel.

  • Define MVP features before coding — todo app, blog CMS, or dashboard
  • Use folder structure: components/, hooks/, lib/, types/
  • Run Lighthouse before demo — fix accessibility and performance regressions

Note

Ship a working MVP first. Polish and refactor after core user flows work end-to-end.

Tip

Apply this in your Week 13 course project before moving on.

Performance

Code-split routes and heavy charts. Target under 200KB initial JS for good mobile performance.

Back to index


Share this article

XLinkedInFacebook
Kazi Rahamatullah

Written by

Kazi Rahamatullah

FullStack Developer

X / TwitterGitHubLinkedIn

Subscribe to my newsletter

Stay up to date and get notified when I share new contents.

No spam ever, unsubscribe anytime