Module 9: Performance & Security

Optimization, Lazy Loading, and Secure Practices.

1. The Cost of JavaScript

Performance isn't just about speed; it's about user retention. A 1MB JavaScript bundle blocks the main thread, freezing the UI. We must split our code and optimize rendering.

Key Techniques

  • Code Splitting (Lazy Loading): Only load the code needed for the current page.
  • Virtualization: Render only the items visible on the screen (essential for long lists).
  • Memoization: Prevent unnecessary re-renders using `React.memo`, `useMemo`, and `useCallback`.
PERF-101 To Do

Implement Code Splitting

User Story

As a mobile user with a slow connection, I want the initial page load to be fast, even if other pages take longer to load later.

Acceptance Criteria
  • Identify heavy routes (e.g., Dashboard, Admin).
  • Replace static imports with React.lazy.
  • Wrap routes in Suspense with a fallback UI.
Code Example (App.tsx)
import { Suspense, lazy } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import LoadingSpinner from './components/LoadingSpinner';

// Lazy load the component
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));

function App() {
  return (
    <BrowserRouter>
      {/* Suspense catches the "loading" state */}
      
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/dashboard" element={<Dashboard />} />
          <Route path="/settings" element={<Settings />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}
PERF-102 To Do

Virtualize Long Lists

User Story

As a user, I want to scroll through a list of 10,000 items smoothly without the browser crashing.

Acceptance Criteria
  • Install react-window or react-virtuoso.
  • Replace a standard map list with a virtualized list component.
  • Verify that only ~10-20 DOM nodes exist at any time.
Code Example (VirtualList.tsx)
import { FixedSizeList as List } from 'react-window';

const Row = ({ index, style }) => (
  <div style={style} className="list-item">
    Row {index}
  </div>
);

const Example = () => (
  <List
    height={400}
    itemCount={10000}
    itemSize={35}
    width={300}
  >
    {Row}
  </List>
);
PERF-103 Memoization Strategy

User Story: As a user, I want the interface to remain responsive even when performing heavy calculations.

Acceptance Criteria:

  • Identify a slow function (e.g., filtering a large list).
  • Wrap the calculation in useMemo.
  • Wrap the callback passed to a child component in useCallback to prevent unnecessary re-renders of the child (if the child is wrapped in React.memo).
SEC-101 To Do

Prevent XSS Attacks

User Story

As a security engineer, I want to ensure that user-generated content cannot execute malicious scripts.

Acceptance Criteria
  • Identify any usage of dangerouslySetInnerHTML.
  • Install dompurify.
  • Sanitize HTML content before rendering.
Code Example (SafeHTML.tsx)
import DOMPurify from 'dompurify';

interface Props {
  dirtyContent: string;
}

const SafeHTML = ({ dirtyContent }: Props) => {
  // Sanitize the string
  const cleanContent = DOMPurify.sanitize(dirtyContent);

  return (
    <div 
      dangerouslySetInnerHTML={{ __html: cleanContent }} 
    />
  );
};

4. Debugging & Refactoring

Debug: Use the React Developer Tools Profiler to identify components that re-render too often. Look for "wasted renders".

Refactor: Improve codebase by breaking large components into smaller, reusable ones. Adopt new practices like migrating class components to Functional Components + Hooks.

🐛 Bug Hunt: The "Memo" Trap

Scenario: You wrapped a component in React.memo, but it still re-renders every time the parent renders.

Why? You are likely passing a new object or new function as a prop.

// ❌ Bad: New object created every render
<Child options={{ color: 'red' }} />

// ❌ Bad: New function created every render
<Child onClick={() => console.log('click')} />

Fix: Use useMemo for objects and useCallback for functions.