Skip to main content

What is React?

  • For Beginners
  • How We Use It
React is a JavaScript library for building user interfaces, created by Facebook (now Meta). Think of it as a way to build interactive websites using reusable pieces called “components.”Key Concepts:
  • Components: Building blocks of your UI (like LEGO pieces)
  • State: Data that can change over time (like a counter value)
  • Props: Data passed from parent to child components (like function arguments)
  • JSX: HTML-like syntax inside JavaScript
Why React?
  • Build once, reuse everywhere (components)
  • Automatically updates UI when data changes
  • Huge ecosystem and community
  • Used by Facebook, Instagram, Netflix, Airbnb, and thousands more
The Mental Model:
Data Changes → React Updates UI Automatically
Instead of manually manipulating the DOM, you describe what the UI should look like, and React handles the updates.

Essential React Concepts

1. Components

  • Function Components
  • Class Components (Legacy)
// Modern React uses function components
function Welcome({ name }: { name: string }) {
  return <h1>Hello, {name}!</h1>
}

// With TypeScript interface
interface UserProps {
  name: string
  age: number
  isActive?: boolean
}

function UserCard({ name, age, isActive = false }: UserProps) {
  return (
    <div className="card">
      <h2>{name}</h2>
      <p>Age: {age}</p>
      {isActive && <span>🟢 Active</span>}
    </div>
  )
}

2. State Management

import { useState } from 'react'

function Counter() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
      <button onClick={() => setCount(prev => prev - 1)}>
        Decrement (using updater function)
      </button>
    </div>
  )
}

3. Effects & Side Effects

import { useEffect, useState } from 'react'

function DataFetcher() {
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)

  useEffect(() => {
    // Runs after component mounts
    fetch('/api/data')
      .then(res => res.json())
      .then(setData)
      .catch(setError)
      .finally(() => setLoading(false))

    // Cleanup function (runs on unmount)
    return () => {
      console.log('Component unmounting')
    }
  }, []) // Empty array = run once on mount

  if (loading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>
  return <div>{JSON.stringify(data)}</div>
}

4. Props & Prop Drilling

// Parent component
function App() {
  const [user, setUser] = useState({ name: 'John', role: 'admin' })

  return <Dashboard user={user} />
}

// Child component
function Dashboard({ user }: { user: User }) {
  return <Sidebar user={user} />
}

// Grandchild component
function Sidebar({ user }: { user: User }) {
  return <UserMenu user={user} />
}

// This is "prop drilling" - passing props through many levels
// Solution: Use Context API or state management library

5. Context API (Avoid Prop Drilling)

import { createContext, useContext, useState } from 'react'

// Create context
const UserContext = createContext<User | null>(null)

// Provider component
function App() {
  const [user, setUser] = useState<User>({ name: 'John' })

  return (
    <UserContext.Provider value={user}>
      <Dashboard />
    </UserContext.Provider>
  )
}

// Consume context anywhere in the tree
function UserMenu() {
  const user = useContext(UserContext)
  return <div>{user?.name}</div>
}

// Custom hook pattern (recommended)
function useUser() {
  const context = useContext(UserContext)
  if (!context) throw new Error('useUser must be used within UserProvider')
  return context
}

100 Essential React Terms

  1. Component - Reusable UI building block
  2. JSX - JavaScript XML syntax
  3. Props - Data passed to components
  4. State - Component’s internal data
  5. Virtual DOM - In-memory representation of UI
  6. Reconciliation - Process of updating the DOM
  7. Rendering - Converting components to UI
  8. Re-rendering - Updating UI when data changes
  9. Mount - Component added to DOM
  10. Unmount - Component removed from DOM
  11. Lifecycle - Stages of component existence
  12. Key - Unique identifier for list items
  13. Ref - Reference to DOM element
  14. Fragment - Group elements without wrapper
  15. Children - Components/elements inside component
  16. Composition - Building complex UIs from simple components
  17. Pure Component - Component with no side effects
  18. Controlled Component - Form input controlled by React state
  19. Uncontrolled Component - Form input managed by DOM
  20. Synthetic Event - React’s cross-browser event wrapper
  1. useState - State management hook
  2. useEffect - Side effects hook
  3. useContext - Context consumption hook
  4. useReducer - Complex state management
  5. useCallback - Memoize functions
  6. useMemo - Memoize computed values
  7. useRef - Persist values across renders
  8. useLayoutEffect - Synchronous useEffect
  9. useImperativeHandle - Customize ref exposure
  10. useDebugValue - Debug custom hooks
  11. useTransition - Non-blocking updates (React 18)
  12. useDeferredValue - Defer expensive updates
  13. useId - Generate unique IDs
  14. useSyncExternalStore - Subscribe to external stores
  15. useInsertionEffect - CSS-in-JS libraries
  16. Custom Hook - Reusable stateful logic
  17. Hook Rules - Rules of Hooks (top-level only, etc.)
  18. Dependency Array - useEffect/useCallback dependencies
  19. Stale Closure - Outdated values in closures
  20. Hook Flow - Order of hook execution
  1. Higher-Order Component (HOC) - Function that wraps components
  2. Render Props - Share code using props
  3. Compound Components - Components that work together
  4. Controlled Props - Props that control state
  5. State Reducer Pattern - Inversion of control for state
  6. Provider Pattern - Context provider pattern
  7. Container/Presentational - Logic/UI separation
  8. Lifting State Up - Move state to common ancestor
  9. Prop Drilling - Passing props through many levels
  10. Code Splitting - Load code on demand
  11. Lazy Loading - Defer component loading
  12. Suspense - Handle async operations
  13. Error Boundary - Catch React errors
  14. Portal - Render outside parent DOM
  15. Forwarding Refs - Pass refs to child components
  16. Memoization - Cache expensive computations
  17. Batching - Group state updates
  18. Concurrent Rendering - Interruptible rendering
  19. Automatic Batching - Batch updates everywhere (React 18)
  20. Transitions - Mark updates as non-urgent
  1. React.memo - Prevent unnecessary re-renders
  2. shouldComponentUpdate - Lifecycle optimization (legacy)
  3. PureComponent - Shallow prop comparison (legacy)
  4. Profiler - Measure render performance
  5. Windowing - Render only visible items
  6. Debouncing - Delay function execution
  7. Throttling - Limit function calls
  8. Virtualization - Render large lists efficiently
  9. Web Workers - Offload heavy computations
  10. Bundle Size - JavaScript file size
  11. Tree Shaking - Remove unused code
  12. Code Splitting - Split into chunks
  13. Prefetching - Load resources early
  14. Hydration - Attach React to SSR HTML
  15. Streaming SSR - Progressive rendering
  1. Local State - Component-specific state
  2. Global State - Application-wide state
  3. Server State - Data from API
  4. URL State - State in URL params
  5. Redux - Predictable state container
  6. Zustand - Lightweight state management
  7. Jotai - Atomic state management
  8. Recoil - Facebook’s state library
  9. MobX - Observable state
  10. XState - State machines
  1. Server Component - Runs on server (Next.js)
  2. Client Component - Runs in browser
  3. Server Actions - Server-side functions
  4. App Router - File-based routing (Next.js 13+)
  5. Pages Router - Legacy routing (Next.js)
  6. Layout - Shared UI across routes
  7. Loading.tsx - Loading states
  8. Error.tsx - Error handling
  9. Route Handlers - API routes
  10. Middleware - Request interception
  11. Static Generation (SSG) - Pre-render at build
  12. Server-Side Rendering (SSR) - Pre-render per request
  13. Incremental Static Regeneration (ISR) - Update static pages
  14. Dynamic Routes - [param] based routes
  15. Parallel Routes - Multiple pages at once

Common Libraries & Tools

Data Fetching

  • TanStack Query (React Query) - Server state management
  • SWR - Stale-while-revalidate
  • Axios - HTTP client
  • GraphQL - Query language
  • tRPC - Type-safe APIs

State Management

  • Zustand - Lightweight, our go-to
  • Redux Toolkit - Redux simplified
  • Jotai - Atomic state
  • Context API - Built-in React

Forms

  • React Hook Form - Performant forms
  • Zod - Schema validation
  • Yup - Validation library
  • Formik - Form management (legacy)

UI Components

  • shadcn/ui - Copy-paste components
  • Radix UI - Headless components
  • Headless UI - Tailwind components
  • Chakra UI - Component library

Styling

  • Tailwind CSS - Utility-first CSS
  • CSS Modules - Scoped styles
  • Styled Components - CSS-in-JS
  • Emotion - CSS-in-JS

Animation

  • Framer Motion - Animation library
  • React Spring - Spring physics
  • GSAP - Professional animations

Routing

  • React Router - Client-side routing
  • TanStack Router - Type-safe routing
  • Next.js Router - Built-in (Next.js)

Testing

  • Vitest - Unit testing
  • Jest - Testing framework
  • React Testing Library - Component testing
  • Playwright - E2E testing

File Structure & Project Organization

Next.js + React Structure

my-nextjs-app/
├── src/
│   ├── app/                          # App Router (Next.js 13+)
│   │   ├── (auth)/                   # Route group (doesn't affect URL)
│   │   │   ├── login/
│   │   │   │   └── page.tsx          # /login route
│   │   │   └── register/
│   │   │       └── page.tsx          # /register route
│   │   ├── (dashboard)/
│   │   │   ├── layout.tsx            # Shared layout for dashboard
│   │   │   ├── page.tsx              # /dashboard route
│   │   │   └── settings/
│   │   │       └── page.tsx          # /dashboard/settings
│   │   ├── api/                      # API routes
│   │   │   ├── users/
│   │   │   │   └── route.ts          # /api/users endpoint
│   │   │   └── auth/
│   │   │       └── route.ts
│   │   ├── layout.tsx                # Root layout (wraps all pages)
│   │   ├── page.tsx                  # Home page (/)
│   │   ├── loading.tsx               # Loading UI
│   │   └── error.tsx                 # Error UI
│   │
│   ├── components/                   # React components
│   │   ├── ui/                       # Base UI components
│   │   │   ├── button.tsx
│   │   │   ├── input.tsx
│   │   │   └── dialog.tsx
│   │   ├── features/                 # Feature-specific components
│   │   │   ├── auth/
│   │   │   │   ├── LoginForm.tsx
│   │   │   │   └── RegisterForm.tsx
│   │   │   └── dashboard/
│   │   │       └── StatsCard.tsx
│   │   └── layouts/                  # Layout components
│   │       ├── Header.tsx
│   │       └── Footer.tsx
│   │
│   ├── hooks/                        # Custom React hooks
│   │   ├── useUser.ts
│   │   ├── useAuth.ts
│   │   └── useDebounce.ts
│   │
│   ├── lib/                          # Utilities & configs
│   │   ├── supabase.ts
│   │   ├── utils.ts
│   │   └── api.ts
│   │
│   ├── types/                        # TypeScript types
│   │   ├── user.ts
│   │   └── api.ts
│   │
│   ├── store/                        # State management
│   │   ├── userStore.ts
│   │   └── appStore.ts
│   │
│   └── styles/                       # Global styles
│       └── globals.css

├── public/                           # Static files
│   ├── images/
│   └── fonts/

├── .env.local                        # Environment variables
├── next.config.js                    # Next.js config
├── tailwind.config.ts                # Tailwind config
├── tsconfig.json                     # TypeScript config
└── package.json

Vite + React Structure

my-vite-app/
├── src/
│   ├── pages/                        # Page components
│   │   ├── Home.tsx
│   │   ├── About.tsx
│   │   └── Dashboard.tsx
│   │
│   ├── components/                   # React components
│   │   ├── ui/
│   │   └── features/
│   │
│   ├── hooks/                        # Custom hooks
│   │
│   ├── lib/                          # Utils
│   │
│   ├── router/                       # Routing config
│   │   └── index.tsx
│   │
│   ├── App.tsx                       # Root component
│   ├── main.tsx                      # Entry point
│   └── index.css

├── public/                           # Static assets
├── .env                              # Environment variables
├── vite.config.ts
└── package.json

Understanding File-Based Routing (Next.js)

1

Basic Routes

Files create routes automatically:
app/page.tsx           → /
app/about/page.tsx     → /about
app/blog/page.tsx      → /blog
2

Dynamic Routes

Use square brackets for parameters:
app/blog/[slug]/page.tsx       → /blog/:slug
app/user/[id]/page.tsx         → /user/:id
app/shop/[...slug]/page.tsx    → /shop/* (catch-all)
// app/blog/[slug]/page.tsx
export default function BlogPost({
  params
}: {
  params: { slug: string }
}) {
  return <h1>Post: {params.slug}</h1>
}
3

Route Groups

Use parentheses to organize without affecting URLs:
app/(marketing)/about/page.tsx     → /about
app/(marketing)/contact/page.tsx   → /contact
app/(shop)/products/page.tsx       → /products
4

Special Files

layout.tsx      → Shared UI for route segment
page.tsx        → Unique UI for route
loading.tsx     → Loading UI (automatic Suspense)
error.tsx       → Error UI (Error Boundary)
not-found.tsx   → 404 UI
route.ts        → API endpoint

Debugging React Applications

1. React DevTools

# Install browser extension
# Chrome: React Developer Tools
# Firefox: React Developer Tools

# Usage:
# - Components tab: Inspect component tree
# - Profiler tab: Measure performance
# - Highlight updates: See what re-renders

2. Common Debugging Patterns

function MyComponent({ user }: { user: User }) {
  console.log('Component rendered', { user })

  useEffect(() => {
    console.log('Effect ran', { user })
  }, [user])

  return <div>{user.name}</div>
}

3. Performance Debugging

import { Profiler } from 'react'

function onRenderCallback(
  id: string,
  phase: 'mount' | 'update',
  actualDuration: number,
  baseDuration: number,
  startTime: number,
  commitTime: number
) {
  console.log({ id, phase, actualDuration })
}

function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <MyComponents />
    </Profiler>
  )
}

Testing Commands

Next.js + React

# Start dev server
npm run dev
# or
pnpm dev

# Specific port
npm run dev -- -p 3001

# TypeScript check
npm run type-check
# or
npx tsc --noEmit

# Lint
npm run lint

# Build
npm run build

# Start production server
npm run start

Vite + React

# Start dev server
npm run dev
# or
pnpm dev

# Specific port
npm run dev -- --port 3001

# Open in browser
npm run dev -- --open

# TypeScript check
npx tsc --noEmit

# Build
npm run build

# Preview production build
npm run preview

Common Issues & Solutions

Problem: Old React versions required importing ReactSolution:
// Not needed in React 17+
// import React from 'react' ❌

// Use new JSX transform (automatic)
export default function App() {
  return <div>Hello</div>
}
Problem: Setting state during render causes infinite loopSolution:
// ❌ Wrong
function Bad() {
  const [count, setCount] = useState(0)
  setCount(1) // Causes infinite loop!
  return <div>{count}</div>
}

// ✅ Correct
function Good() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    setCount(1) // OK in effect
  }, [])

  return <div>{count}</div>
}
Problem: Missing or wrong dependenciesSolution:
// ❌ Wrong - runs on every render
useEffect(() => {
  fetchData()
}) // No dependency array!

// ❌ Wrong - object/array recreated each render
useEffect(() => {
  fetchData(filter)
}, [filter]) // If filter is an object

// ✅ Correct
useEffect(() => {
  fetchData()
}, []) // Run once

// ✅ Or memoize objects
const filter = useMemo(() => ({ status: 'active' }), [])
useEffect(() => {
  fetchData(filter)
}, [filter])
Problem: Arrow functions vs regular functionsSolution:
// ❌ Wrong (class component)
<button onClick={this.handleClick}>

// ✅ Correct
<button onClick={() => this.handleClick()}>

// ✅ Or use arrow function in class
handleClick = () => {
  // this works correctly
}

// ✅ Best: Use function components
function Component() {
  const handleClick = () => {
    // No 'this' issues!
  }
  return <button onClick={handleClick}>
}
Problem: Missing unique key for list itemsSolution:
// ❌ Wrong
{items.map(item => <div>{item.name}</div>)}

// ❌ Wrong (index as key - unstable)
{items.map((item, i) => <div key={i}>{item.name}</div>)}

// ✅ Correct (unique stable ID)
{items.map(item => <div key={item.id}>{item.name}</div>)}
Problem: Function captures old valuesSolution:
function Counter() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    const interval = setInterval(() => {
      // ❌ Always logs 0 (stale closure)
      console.log(count)

      // ✅ Use updater function
      setCount(c => c + 1)
    }, 1000)

    return () => clearInterval(interval)
  }, []) // Empty deps = stale closure
}

Best Practices Checklist

1

Component Design

  • Use functional components with hooks
  • Keep components small and focused
  • Separate logic from presentation
  • Use TypeScript for type safety
  • Extract reusable logic into custom hooks
2

State Management

  • Start with local state (useState)
  • Lift state up when needed
  • Use Context for app-wide state
  • Use Zustand/Redux for complex global state
  • Keep state as close to where it’s used as possible
3

Performance

  • Use React.memo for expensive components
  • Memoize callbacks with useCallback
  • Memoize computed values with useMemo
  • Code split with React.lazy
  • Virtualize long lists
4

Error Handling

  • Wrap components in Error Boundaries
  • Handle async errors in useEffect
  • Validate props with TypeScript
  • Show user-friendly error messages
5

Testing

  • Write tests for critical paths
  • Test user behavior, not implementation
  • Use React Testing Library
  • Mock API calls
  • Test accessibility
Common Pitfalls:
  • Don’t mutate state directly (use setState)
  • Don’t call hooks conditionally
  • Don’t forget cleanup in useEffect
  • Don’t use index as key for dynamic lists
  • Don’t optimize prematurely

Quick Reference: Hooks Cheat Sheet

// State
const [state, setState] = useState(initialValue)
setState(newValue)
setState(prev => prev + 1) // Updater function

// Effect
useEffect(() => {
  // Side effect here
  return () => {
    // Cleanup
  }
}, [dependencies])

// Context
const value = useContext(MyContext)

// Ref
const ref = useRef(initialValue)
ref.current = newValue

// Memoization
const memoizedValue = useMemo(() => computeExpensive(), [deps])
const memoizedCallback = useCallback(() => {}, [deps])

// Reducer
const [state, dispatch] = useReducer(reducer, initialState)
dispatch({ type: 'INCREMENT' })

// Custom Hook
function useCustomHook() {
  const [state, setState] = useState()
  // ... logic
  return state
}
Master these concepts in order:
  1. Components & JSX
  2. Props & State
  3. useEffect & Side Effects
  4. Custom Hooks
  5. Performance Optimization
  6. Advanced Patterns