学习目标

  • 理解React性能优化原理
  • 掌握组件优化技巧
  • 学会渲染优化方法
  • 理解内存管理和清理
  • 构建高性能React应用

学习时间安排

总时长:8-9小时

  • 性能优化基础:2小时
  • 组件优化技巧:2.5小时
  • 渲染优化:2小时
  • 内存管理:1小时
  • 实践项目:2-3小时

第一部分:性能优化基础 (2小时)

1.1 React性能优化原理

性能问题识别(详细注释版)
// src/utils/performanceMonitor.js
// 性能监控工具
import { useEffect, useRef } from 'react';
// 定义性能监控Hook
export function usePerformanceMonitor(componentName) {
// 使用useRef Hook保存渲染开始时间
const renderStartTime = useRef(null);
// 使用useRef Hook保存渲染次数
const renderCount = useRef(0);
// 组件挂载时记录开始时间
useEffect(() => {
renderStartTime.current = performance.now();
renderCount.current = 0;
// 返回清理函数
return () => {
const renderTime = performance.now() - renderStartTime.current;
const averageRenderTime = renderCount.current > 0
? renderTime / renderCount.current
: 0;
console.log(`Component: ${componentName}`);
console.log(`Total render time: ${renderTime.toFixed(2)}ms`);
console.log(`Total renders: ${renderCount.current}`);
console.log(`Average render time: ${averageRenderTime.toFixed(2)}ms`);
};
}, [componentName]);
// 每次渲染时记录
useEffect(() => {
renderCount.current += 1;
const renderTime = performance.now() - (renderStartTime.current || 0);
if (renderTime > 16) {
console.warn(`Slow render detected in ${componentName}: ${renderTime.toFixed(2)}ms`);
}
});
}
// 定义性能测量函数
export function measurePerformance(fn, label) {
const start = performance.now();
const result = fn();
const end = performance.now();
const duration = end - start;
console.log(`${label}: ${duration.toFixed(2)}ms`);
if (duration > 16) {
console.warn(`Slow operation detected: ${label} took ${duration.toFixed(2)}ms`);
}
return result;
}
// 定义性能分析器
export class PerformanceProfiler {
constructor() {
this.metrics = [];
this.startTime = null;
}
// 开始测量
start(label) {
this.startTime = performance.now();
this.currentLabel = label;
}
// 结束测量
end() {
if (this.startTime && this.currentLabel) {
const duration = performance.now() - this.startTime;
this.metrics.push({
label: this.currentLabel,
duration: duration,
timestamp: new Date().toISOString()
});
if (duration > 16) {
console.warn(`Slow operation: ${this.currentLabel} took ${duration.toFixed(2)}ms`);
}
this.startTime = null;
this.currentLabel = null;
}
}
// 获取报告
getReport() {
const totalTime = this.metrics.reduce((sum, m) => sum + m.duration, 0);
const averageTime = this.metrics.length > 0
? totalTime / this.metrics.length
: 0;
return {
totalOperations: this.metrics.length,
totalTime: totalTime.toFixed(2),
averageTime: averageTime.toFixed(2),
metrics: this.metrics
};
}
// 清除记录
clear() {
this.metrics = [];
}
}

1.2 React DevTools Profiler

Profiler组件使用(详细注释版)
// src/components/ProfiledComponent.js
// 导入React和Profiler
import React, { Profiler } from 'react';
// 定义性能回调函数
// 这个函数会在组件渲染时被调用
function onRenderCallback(id, phase, actualDuration, baseDuration, startTime, commitTime) {
// id: 被测量的组件的id
// phase: 渲染阶段,'mount' 或 'update'
// actualDuration: 本次渲染实际花费的时间(毫秒)
// baseDuration: 估算的不使用优化的情况下渲染需要的时间
// startTime: 本次渲染开始的时间戳
// commitTime: React提交本次更新的时间戳
console.log('Profiler:', {
id,
phase,
actualDuration: `${actualDuration.toFixed(2)}ms`,
baseDuration: `${baseDuration.toFixed(2)}ms`,
startTime: `${startTime.toFixed(2)}ms`,
commitTime: `${commitTime.toFixed(2)}ms`
});
// 如果渲染时间过长,发出警告
if (actualDuration > 16) {
console.warn(`Slow render detected: ${id} took ${actualDuration.toFixed(2)}ms`);
}
}
// 定义被测量的组件
function ExpensiveComponent({ data }) {
// 模拟昂贵的计算
const processedData = data.map(item => {
let sum = 0;
for (let i = 0; i < 1000; i++) {
sum += item.value * i;
}
return { ...item, processed: sum };
});
return (
<div>
  <h3>Expensive Component</h3>
    <ul>
      {processedData.map(item => (
      <li key={item.id}>{item.name}: {item.processed}</li>
        ))}
        </ul>
          </div>
            );
            }
            // 定义使用Profiler的组件
            function ProfiledComponent({ data }) {
            return (
            <Profiler id="ExpensiveComponent" onRender={onRenderCallback}>
              <ExpensiveComponent data={data} />
                </Profiler>
                  );
                  }
                  // 导出组件
                  export default ProfiledComponent;

第二部分:组件优化技巧 (2.5小时)

2.1 React.memo优化

基础memo使用(详细注释版)
// src/components/MemoizedComponent.js
// 导入React和memo
import React, { memo } from 'react';
// 定义普通组件
function RegularComponent({ name, age, address }) {
console.log('RegularComponent rendered');
return (
<div>
  <h3>Regular Component</h3>
    <p>Name: {name}</p>
      <p>Age: {age}</p>
        <p>Address: {address.street}, {address.city}</p>
          </div>
            );
            }
            // 定义使用memo优化的组件
            // memo会对props进行浅比较,只有当props发生变化时才重新渲染
            const MemoizedComponent = memo(function MemoizedComponent({ name, age, address }) {
            console.log('MemoizedComponent rendered');
            return (
            <div>
              <h3>Memoized Component</h3>
                <p>Name: {name}</p>
                  <p>Age: {age}</p>
                    <p>Address: {address.street}, {address.city}</p>
                      </div>
                        );
                        });
                        // 定义自定义比较函数
                        // 只有当name或age变化时才重新渲染,忽略address的变化
                        const CustomMemoizedComponent = memo(
                        function CustomMemoizedComponent({ name, age, address }) {
                        console.log('CustomMemoizedComponent rendered');
                        return (
                        <div>
                          <h3>Custom Memoized Component</h3>
                            <p>Name: {name}</p>
                              <p>Age: {age}</p>
                                <p>Address: {address.street}, {address.city}</p>
                                  </div>
                                    );
                                    },
                                    // 自定义比较函数
                                    // 返回true表示props相等,不重新渲染
                                    // 返回false表示props不相等,需要重新渲染
                                    (prevProps, nextProps) => {
                                    return prevProps.name === nextProps.name &&
                                    prevProps.age === nextProps.age;
                                    }
                                    );
                                    // 导出组件
                                    export { RegularComponent, MemoizedComponent, CustomMemoizedComponent };
memo高级用法(详细注释版)
// src/components/AdvancedMemo.js
// 导入React、memo、useState、useCallback
import React, { memo, useState, useCallback } from 'react';
// 定义子组件
const ChildComponent = memo(function ChildComponent({
name,
onClick,
items
}) {
console.log('ChildComponent rendered');
return (
<div>
  <h3>Child Component</h3>
    <p>Name: {name}</p>
      <button onClick={onClick}>Click me</button>
        <ul>
          {items.map(item => (
          <li key={item.id}>{item.text}</li>
            ))}
            </ul>
              </div>
                );
                });
                // 定义父组件
                function AdvancedMemo() {
                // 使用useState Hook管理状态
                const [count, setCount] = useState(0);
                const [name, setName] = useState('John');
                const [items, setItems] = useState([
                { id: 1, text: 'Item 1' },
                { id: 2, text: 'Item 2' }
                ]);
                // 使用useCallback Hook记忆化函数
                // 只有当依赖项变化时才创建新函数
                const handleClick = useCallback(() => {
                console.log('Button clicked');
                setCount(prev => prev + 1);
                }, []);
                // 处理添加项目
                const handleAddItem = useCallback(() => {
                setItems(prev => [...prev, {
                id: Date.now(),
                text: `Item ${prev.length + 1}`
                }]);
                }, []);
                return (
                <div>
                  <h2>Advanced Memo Example</h2>
                    <p>Count: {count}</p>
                      <div>
                        <input
                        type="text"
                        value={name}
                        onChange={(e) => setName(e.target.value)}
                        placeholder="Enter name"
                        />
                        </div>
                          <div>
                            <button onClick={handleAddItem}>Add Item</button>
                              </div>
                                {/* 使用memo优化的子组件 */}
                                <ChildComponent
                                name={name}
                                onClick={handleClick}
                                items={items}
                                />
                                </div>
                                  );
                                  }
                                  // 导出组件
                                  export default AdvancedMemo;

2.2 useMemo Hook

useMemo基础使用(详细注释版)
// src/components/UseMemoExample.js
// 导入React、useState、useMemo
import React, { useState, useMemo } from 'react';
// 定义昂贵的计算函数
function expensiveCalculation(numbers) {
console.log('Expensive calculation running...');
// 模拟昂贵的计算
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
for (let j = 0; j < 1000000; j++) {
sum += numbers[i] * j;
}
}
return sum;
}
// 定义使用useMemo的组件
function UseMemoExample() {
// 使用useState Hook管理状态
const [numbers, setNumbers] = useState([1, 2, 3, 4, 5]);
const [count, setCount] = useState(0);
const [filter, setFilter] = useState('all');
// 使用useMemo Hook记忆化计算结果
// 只有当numbers变化时才重新计算
const expensiveValue = useMemo(() => {
return expensiveCalculation(numbers);
}, [numbers]);
// 使用useMemo Hook过滤和排序数据
// 只有当numbers或filter变化时才重新计算
const filteredAndSortedNumbers = useMemo(() => {
console.log('Filtering and sorting...');
let filtered = numbers;
if (filter === 'even') {
filtered = numbers.filter(n => n % 2 === 0);
} else if (filter === 'odd') {
filtered = numbers.filter(n => n % 2 !== 0);
}
return [...filtered].sort((a, b) => a - b);
}, [numbers, filter]);
// 处理添加数字
const handleAddNumber = () => {
setNumbers(prev => [...prev, Math.floor(Math.random() * 100)]);
};
// 处理移除数字
const handleRemoveNumber = (index) => {
setNumbers(prev => prev.filter((_, i) => i !== index));
};
return (
<div>
  <h2>useMemo Example</h2>
    <div>
      <p>Count: {count}</p>
        <button onClick={() => setCount(count + 1)}>Increment Count</button>
          </div>
            <div>
              <label>
                Filter:
                <select value={filter} onChange={(e) => setFilter(e.target.value)}>
                  <option value="all">All</option>
                    <option value="even">Even</option>
                      <option value="odd">Odd</option>
                        </select>
                          </label>
                            </div>
                              <div>
                                <button onClick={handleAddNumber}>Add Number</button>
                                  <ul>
                                    {numbers.map((number, index) => (
                                    <li key={index}>
                                      {number}
                                      <button onClick={() => handleRemoveNumber(index)}>Remove</button>
                                        </li>
                                          ))}
                                          </ul>
                                            </div>
                                              <div>
                                                <h3>Filtered and Sorted Numbers:</h3>
                                                  <ul>
                                                    {filteredAndSortedNumbers.map((number, index) => (
                                                    <li key={index}>{number}</li>
                                                      ))}
                                                      </ul>
                                                        </div>
                                                          <div>
                                                            <h3>Expensive Calculation Result:</h3>
                                                              <p>{expensiveValue}</p>
                                                                <p>Note: This value is memoized and only recalculates when numbers change.</p>
                                                                  </div>
                                                                    </div>
                                                                      );
                                                                      }
                                                                      // 导出组件
                                                                      export default UseMemoExample;

2.3 useCallback Hook

useCallback基础使用(详细注释版)
// src/components/UseCallbackExample.js
// 导入React、useState、useCallback、memo
import React, { useState, useCallback, memo } from 'react';
// 定义使用memo优化的子组件
const Button = memo(function Button({ onClick, label }) {
console.log(`Button ${label} rendered`);
return (
<button onClick={onClick} className="btn">
  {label}
  </button>
    );
    });
    // 定义使用memo优化的列表项组件
    const ListItem = memo(function ListItem({ item, onDelete, onEdit }) {
    console.log(`ListItem ${item.id} rendered`);
    return (
    <div className="list-item">
      <span>{item.name}</span>
        <div>
          <button onClick={() => onEdit(item.id)}>Edit</button>
            <button onClick={() => onDelete(item.id)}>Delete</button>
              </div>
                </div>
                  );
                  });
                  // 定义使用useCallback的组件
                  function UseCallbackExample() {
                  // 使用useState Hook管理状态
                  const [count, setCount] = useState(0);
                  const [items, setItems] = useState([
                  { id: 1, name: 'Item 1' },
                  { id: 2, name: 'Item 2' },
                  { id: 3, name: 'Item 3' }
                  ]);
                  // 使用useCallback Hook记忆化函数
                  // 这个函数不会在每次渲染时重新创建
                  const handleIncrement = useCallback(() => {
                  setCount(prev => prev + 1);
                  }, []);
                  // 使用useCallback Hook记忆化函数
                  // 这个函数不会在每次渲染时重新创建
                  const handleDecrement = useCallback(() => {
                  setCount(prev => prev - 1);
                  }, []);
                  // 使用useCallback Hook记忆化函数
                  // 只有当items变化时才创建新函数
                  const handleDelete = useCallback((id) => {
                  setItems(prev => prev.filter(item => item.id !== id));
                  }, []);
                  // 使用useCallback Hook记忆化函数
                  // 这个函数不会在每次渲染时重新创建
                  const handleEdit = useCallback((id) => {
                  const newName = prompt('Enter new name:');
                  if (newName) {
                  setItems(prev => prev.map(item =>
                  item.id === id ? { ...item, name: newName } : item
                  ));
                  }
                  }, []);
                  // 处理添加项目
                  const handleAddItem = useCallback(() => {
                  setItems(prev => [...prev, {
                  id: Date.now(),
                  name: `Item ${prev.length + 1}`
                  }]);
                  }, []);
                  return (
                  <div>
                    <h2>useCallback Example</h2>
                      <div>
                        <p>Count: {count}</p>
                          <Button onClick={handleIncrement} label="Increment" />
                            <Button onClick={handleDecrement} label="Decrement" />
                              </div>
                                <div>
                                  <button onClick={handleAddItem}>Add Item</button>
                                    <ul>
                                      {items.map(item => (
                                      <ListItem
                                      key={item.id}
                                      item={item}
                                      onDelete={handleDelete}
                                      onEdit={handleEdit}
                                      />
                                      ))}
                                      </ul>
                                        </div>
                                          </div>
                                            );
                                            }
                                            // 导出组件
                                            export default UseCallbackExample;

2.4 组件拆分优化

组件拆分示例(详细注释版)
// src/components/OptimizedList.js
// 导入React、useState、useCallback、memo、useMemo
import React, { useState, useCallback, memo, useMemo } from 'react';
// 定义列表项组件
// 使用memo优化,只有当props变化时才重新渲染
const ListItem = memo(function ListItem({
item,
isSelected,
onSelect,
onToggle
}) {
console.log(`ListItem ${item.id} rendered`);
return (
<div
className={`list-item ${isSelected ? 'selected' : ''}`}
onClick={() => onSelect(item.id)}
>
<input
type="checkbox"
checked={item.completed}
onChange={() => onToggle(item.id)}
onClick={(e) => e.stopPropagation()}
/>
<span>{item.name}</span>
  <span className="item-date">
    {new Date(item.createdAt).toLocaleDateString()}
    </span>
      </div>
        );
        });
        // 定义列表头部组件
        // 使用memo优化
        const ListHeader = memo(function ListHeader({
        total,
        selected,
        onSelectAll,
        onClearSelection
        }) {
        console.log('ListHeader rendered');
        return (
        <div className="list-header">
          <h3>Items ({total})</h3>
            <div>
              <button onClick={onSelectAll}>Select All</button>
                <button onClick={onClearSelection}>Clear Selection</button>
                  <span>Selected: {selected}</span>
                    </div>
                      </div>
                        );
                        });
                        // 定义列表过滤器组件
                        // 使用memo优化
                        const ListFilter = memo(function ListFilter({
                        filter,
                        onFilterChange
                        }) {
                        console.log('ListFilter rendered');
                        return (
                        <div className="list-filter">
                          <label>
                            Filter:
                            <select value={filter} onChange={(e) => onFilterChange(e.target.value)}>
                              <option value="all">All</option>
                                <option value="completed">Completed</option>
                                  <option value="pending">Pending</option>
                                    </select>
                                      </label>
                                        </div>
                                          );
                                          });
                                          // 定义优化后的列表组件
                                          function OptimizedList() {
                                          // 使用useState Hook管理状态
                                          const [items, setItems] = useState([
                                          { id: 1, name: 'Item 1', completed: false, createdAt: new Date() },
                                          { id: 2, name: 'Item 2', completed: true, createdAt: new Date() },
                                          { id: 3, name: 'Item 3', completed: false, createdAt: new Date() }
                                          ]);
                                          const [selectedItems, setSelectedItems] = useState([]);
                                          const [filter, setFilter] = useState('all');
                                          // 使用useMemo Hook记忆化过滤后的列表
                                          // 只有当items或filter变化时才重新计算
                                          const filteredItems = useMemo(() => {
                                          console.log('Filtering items...');
                                          switch (filter) {
                                          case 'completed':
                                          return items.filter(item => item.completed);
                                          case 'pending':
                                          return items.filter(item => !item.completed);
                                          default:
                                          return items;
                                          }
                                          }, [items, filter]);
                                          // 使用useCallback Hook记忆化函数
                                          const handleSelect = useCallback((id) => {
                                          setSelectedItems(prev =>
                                          prev.includes(id)
                                          ? prev.filter(itemId => itemId !== id)
                                          : [...prev, id]
                                          );
                                          }, []);
                                          // 使用useCallback Hook记忆化函数
                                          const handleToggle = useCallback((id) => {
                                          setItems(prev => prev.map(item =>
                                          item.id === id ? { ...item, completed: !item.completed } : item
                                          ));
                                          }, []);
                                          // 使用useCallback Hook记忆化函数
                                          const handleSelectAll = useCallback(() => {
                                          setSelectedItems(filteredItems.map(item => item.id));
                                          }, [filteredItems]);
                                          // 使用useCallback Hook记忆化函数
                                          const handleClearSelection = useCallback(() => {
                                          setSelectedItems([]);
                                          }, []);
                                          // 使用useCallback Hook记忆化函数
                                          const handleFilterChange = useCallback((newFilter) => {
                                          setFilter(newFilter);
                                          }, []);
                                          return (
                                          <div className="optimized-list">
                                            <ListHeader
                                            total={items.length}
                                            selected={selectedItems.length}
                                            onSelectAll={handleSelectAll}
                                            onClearSelection={handleClearSelection}
                                            />
                                            <ListFilter
                                            filter={filter}
                                            onFilterChange={handleFilterChange}
                                            />
                                            <div className="list-items">
                                              {filteredItems.map(item => (
                                              <ListItem
                                              key={item.id}
                                              item={item}
                                              isSelected={selectedItems.includes(item.id)}
                                              onSelect={handleSelect}
                                              onToggle={handleToggle}
                                              />
                                              ))}
                                              </div>
                                                </div>
                                                  );
                                                  }
                                                  // 导出组件
                                                  export default OptimizedList;

第三部分:渲染优化 (2小时)

3.1 虚拟滚动

虚拟滚动实现(详细注释版)
// src/components/VirtualizedList.js
// 导入React、useState、useRef、useMemo、useCallback
import React, { useState, useRef, useMemo, useCallback, useEffect } from 'react';
// 定义虚拟滚动组件
function VirtualizedList({ items, itemHeight = 50, containerHeight = 400 }) {
// 使用useState Hook管理状态
const [scrollTop, setScrollTop] = useState(0);
// 使用useRef Hook保存容器引用
const containerRef = useRef(null);
// 计算可见范围
// 使用useMemo Hook记忆化计算结果
const visibleRange = useMemo(() => {
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(
startIndex + Math.ceil(containerHeight / itemHeight) + 1,
items.length
);
return { startIndex, endIndex };
}, [scrollTop, itemHeight, containerHeight, items.length]);
// 计算可见项目
const visibleItems = useMemo(() => {
return items.slice(visibleRange.startIndex, visibleRange.endIndex);
}, [items, visibleRange.startIndex, visibleRange.endIndex]);
// 计算总高度
const totalHeight = items.length * itemHeight;
// 计算偏移量
const offsetY = visibleRange.startIndex * itemHeight;
// 处理滚动事件
const handleScroll = useCallback((e) => {
setScrollTop(e.target.scrollTop);
}, []);
return (
<div
ref={containerRef}
className="virtualized-list"
style={{
height: containerHeight,
overflow: 'auto',
position: 'relative'
}}
onScroll={handleScroll}
>
{/* 占位元素,保持总高度 */}
<div style={{ height: totalHeight, position: 'relative' }}>
  {/* 可见项目容器 */}
  <div
  style={{
  position: 'absolute',
  top: offsetY,
  left: 0,
  right: 0
  }}
  >
  {visibleItems.map((item, index) => (
  <div
  key={item.id || visibleRange.startIndex + index}
  style={{
  height: itemHeight,
  display: 'flex',
  alignItems: 'center',
  padding: '0 10px',
  borderBottom: '1px solid #ddd'
  }}
  >
  {item.content || item.name || `Item ${visibleRange.startIndex + index + 1}`}
  </div>
    ))}
    </div>
      </div>
        </div>
          );
          }
          // 定义使用虚拟滚动的组件
          function VirtualizedListExample() {
          // 生成大量数据
          const items = useMemo(() => {
          return Array.from({ length: 10000 }, (_, i) => ({
          id: i,
          name: `Item ${i + 1}`,
          content: `This is item ${i + 1} with some content`
          }));
          }, []);
          return (
          <div>
            <h2>Virtualized List Example</h2>
              <p>Total items: {items.length}</p>
                <VirtualizedList items={items} itemHeight={50} containerHeight={400} />
                  </div>
                    );
                    }
                    // 导出组件
                    export default VirtualizedListExample;

3.2 懒加载和代码分割

懒加载组件(详细注释版)
// src/components/LazyLoadedComponent.js
// 导入React、lazy、Suspense
import React, { lazy, Suspense } from 'react';
// 使用lazy函数动态导入组件
// 这会将组件代码分割成单独的chunk,只在需要时加载
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const AnotherHeavyComponent = lazy(() => import('./AnotherHeavyComponent'));
// 定义加载中组件
function LoadingFallback() {
return (
<div className="loading-fallback">
  <div className="spinner"></div>
    <p>Loading component...</p>
      </div>
        );
        }
        // 定义使用懒加载的组件
        function LazyLoadedComponent() {
        const [showHeavy, setShowHeavy] = React.useState(false);
        const [showAnother, setShowAnother] = React.useState(false);
        return (
        <div>
          <h2>Lazy Loaded Components</h2>
            <div>
              <button onClick={() => setShowHeavy(!showHeavy)}>
                {showHeavy ? 'Hide' : 'Show'} Heavy Component
                </button>
                  <button onClick={() => setShowAnother(!showAnother)}>
                    {showAnother ? 'Hide' : 'Show'} Another Heavy Component
                    </button>
                      </div>
                        {/* 使用Suspense包装懒加载组件 */}
                        {/* fallback属性指定加载时显示的组件 */}
                        <Suspense fallback={<LoadingFallback />}>
                          {showHeavy && <HeavyComponent />}
                            {showAnother && <AnotherHeavyComponent />}
                              </Suspense>
                                </div>
                                  );
                                  }
                                  // 导出组件
                                  export default LazyLoadedComponent;
路由级别的代码分割(详细注释版)
// src/App.js
// 导入React、lazy、Suspense
import React, { lazy, Suspense } from 'react';
// 导入路由组件
import { BrowserRouter, Routes, Route } from 'react-router-dom';
// 导入布局组件
import Layout from './components/Layout';
// 使用lazy函数动态导入页面组件
// 这些组件会被分割成独立的chunk
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Blog = lazy(() => import('./pages/Blog'));
const Contact = lazy(() => import('./pages/Contact'));
// 定义加载中组件
function PageLoader() {
return (
<div className="page-loader">
  <div className="spinner"></div>
    <p>Loading page...</p>
      </div>
        );
        }
        // 定义主应用组件
        function App() {
        return (
        <BrowserRouter>
          <Layout>
            {/* 使用Suspense包装所有路由 */}
            <Suspense fallback={<PageLoader />}>
              <Routes>
                <Route path="/" element={<Home />} />
                  <Route path="/about" element={<About />} />
                    <Route path="/blog" element={<Blog />} />
                      <Route path="/contact" element={<Contact />} />
                        </Routes>
                          </Suspense>
                            </Layout>
                              </BrowserRouter>
                                );
                                }
                                // 导出App组件
                                export default App;

3.3 图片懒加载

图片懒加载组件(详细注释版)
// src/components/LazyImage.js
// 导入React、useState、useRef、useEffect
import React, { useState, useRef, useEffect } from 'react';
// 定义懒加载图片组件
function LazyImage({
src,
alt,
placeholder = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg"%3E%3C/svg%3E',
className = '',
...props
}) {
// 使用useState Hook管理加载状态
const [isLoaded, setIsLoaded] = useState(false);
const [isInView, setIsInView] = useState(false);
// 使用useRef Hook保存图片引用
const imgRef = useRef(null);
// 使用IntersectionObserver API检测图片是否进入视口
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
setIsInView(true);
observer.disconnect();
}
});
},
{
rootMargin: '50px' // 提前50px开始加载
}
);
if (imgRef.current) {
observer.observe(imgRef.current);
}
return () => {
if (imgRef.current) {
observer.unobserve(imgRef.current);
}
};
}, []);
// 处理图片加载完成
const handleLoad = () => {
setIsLoaded(true);
};
// 处理图片加载错误
const handleError = () => {
console.error('Failed to load image:', src);
};
return (
<div
ref={imgRef}
className={`lazy-image-container ${className}`}
style={{ position: 'relative', overflow: 'hidden' }}
>
{/* 占位图片 */}
{!isLoaded && (
<img
src={placeholder}
alt=""
className="lazy-image-placeholder"
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
objectFit: 'cover',
filter: 'blur(10px)',
transition: 'opacity 0.3s'
}}
/>
)}
{/* 实际图片 */}
{isInView && (
<img
src={src}
alt={alt}
onLoad={handleLoad}
onError={handleError}
className={`lazy-image ${isLoaded ? 'loaded' : ''}`}
style={{
width: '100%',
height: '100%',
objectFit: 'cover',
opacity: isLoaded ? 1 : 0,
transition: 'opacity 0.3s'
}}
{...props}
/>
)}
</div>
  );
  }
  // 定义图片网格组件
  function LazyImageGrid({ images }) {
  return (
  <div className="image-grid">
    {images.map((image, index) => (
    <LazyImage
    key={image.id || index}
    src={image.src}
    alt={image.alt || `Image ${index + 1}`}
    className="grid-image"
    />
    ))}
    </div>
      );
      }
      // 导出组件
      export { LazyImage, LazyImageGrid };

第四部分:内存管理 (1小时)

4.1 内存泄漏预防

内存泄漏预防(详细注释版)
// src/hooks/useCleanup.js
// 导入React、useEffect、useRef
import { useEffect, useRef } from 'react';
// 定义清理Hook
export function useCleanup(cleanupFn) {
// 使用useRef Hook保存清理函数
const cleanupRef = useRef(cleanupFn);
// 更新清理函数引用
useEffect(() => {
cleanupRef.current = cleanupFn;
}, [cleanupFn]);
// 组件卸载时执行清理
useEffect(() => {
return () => {
if (cleanupRef.current) {
cleanupRef.current();
}
};
}, []);
}
// 定义事件监听器Hook
export function useEventListener(eventName, handler, element = window) {
// 使用useRef Hook保存处理函数
const handlerRef = useRef(handler);
// 更新处理函数引用
useEffect(() => {
handlerRef.current = handler;
}, [handler]);
// 添加和移除事件监听器
useEffect(() => {
const eventListener = (event) => {
handlerRef.current(event);
};
if (element && element.addEventListener) {
element.addEventListener(eventName, eventListener);
// 返回清理函数,移除事件监听器
return () => {
element.removeEventListener(eventName, eventListener);
};
}
}, [eventName, element]);
}
// 定义定时器Hook
export function useInterval(callback, delay) {
// 使用useRef Hook保存回调函数
const callbackRef = useRef(callback);
// 更新回调函数引用
useEffect(() => {
callbackRef.current = callback;
}, [callback]);
// 设置和清理定时器
useEffect(() => {
if (delay !== null) {
const interval = setInterval(() => {
callbackRef.current();
}, delay);
// 返回清理函数,清除定时器
return () => clearInterval(interval);
}
}, [delay]);
}
// 定义超时Hook
export function useTimeout(callback, delay) {
// 使用useRef Hook保存回调函数
const callbackRef = useRef(callback);
// 更新回调函数引用
useEffect(() => {
callbackRef.current = callback;
}, [callback]);
// 设置和清理超时
useEffect(() => {
if (delay !== null) {
const timeout = setTimeout(() => {
callbackRef.current();
}, delay);
// 返回清理函数,清除超时
return () => clearTimeout(timeout);
}
}, [delay]);
}

4.2 组件清理示例

完整清理示例(详细注释版)
// src/components/CleanupExample.js
// 导入React、useState、useEffect、useRef
import React, { useState, useEffect, useRef } from 'react';
// 导入清理Hooks
import { useEventListener, useInterval, useTimeout } from '../hooks/useCleanup';
// 定义需要清理的组件
function CleanupExample() {
// 使用useState Hook管理状态
const [count, setCount] = useState(0);
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const [isVisible, setIsVisible] = useState(true);
// 使用useRef Hook保存订阅引用
const subscriptionRef = useRef(null);
// 使用useRef Hook保存WebSocket引用
const wsRef = useRef(null);
// 使用useEventListener Hook监听鼠标移动
useEventListener('mousemove', (e) => {
setMousePosition({ x: e.clientX, y: e.clientY });
});
// 使用useInterval Hook设置定时器
useInterval(() => {
setCount(prev => prev + 1);
}, 1000);
// 模拟订阅清理
useEffect(() => {
// 模拟创建订阅
subscriptionRef.current = {
unsubscribe: () => {
console.log('Subscription unsubscribed');
}
};
// 返回清理函数
return () => {
if (subscriptionRef.current) {
subscriptionRef.current.unsubscribe();
subscriptionRef.current = null;
}
};
}, []);
// 模拟WebSocket连接清理
useEffect(() => {
// 模拟WebSocket连接
wsRef.current = {
close: () => {
console.log('WebSocket closed');
}
};
// 返回清理函数
return () => {
if (wsRef.current) {
wsRef.current.close();
wsRef.current = null;
}
};
}, []);
// 处理切换可见性
const handleToggleVisibility = () => {
setIsVisible(prev => !prev);
};
return (
<div>
  <h2>Cleanup Example</h2>
    <div>
      <p>Count: {count}</p>
        <p>Mouse Position: {mousePosition.x}, {mousePosition.y}</p>
          <p>Component is {isVisible ? 'visible' : 'hidden'}</p>
            </div>
              <button onClick={handleToggleVisibility}>
                Toggle Visibility
                </button>
                  {isVisible && (
                  <div>
                    <h3>Visible Content</h3>
                      <p>This content will be cleaned up when hidden.</p>
                        </div>
                          )}
                          </div>
                            );
                            }
                            // 导出组件
                            export default CleanupExample;

第五部分:实践项目(详细注释版)

项目:高性能数据表格

主应用组件(详细注释版)
// src/App.js
// 导入React
import React from 'react';
// 导入组件
import OptimizedDataTable from './components/OptimizedDataTable';
// 导入样式
import './App.css';
// 定义主应用组件
function App() {
// 生成大量数据
const generateData = (count) => {
return Array.from({ length: count }, (_, i) => ({
id: i + 1,
name: `Item ${i + 1}`,
category: ['Category A', 'Category B', 'Category C'][i % 3],
price: Math.floor(Math.random() * 1000),
status: ['Active', 'Inactive', 'Pending'][i % 3],
date: new Date(Date.now() - Math.random() * 10000000000).toISOString(),
description: `This is a description for item ${i + 1}`
}));
};
const data = generateData(10000);
return (
<div className="App">
  <header className="App-header">
    <h1>High Performance Data Table</h1>
      <p>Total items: {data.length}</p>
        </header>
          <main>
            <OptimizedDataTable data={data} />
              </main>
                </div>
                  );
                  }
                  // 导出App组件
                  export default App;
优化的数据表格组件(详细注释版)
// src/components/OptimizedDataTable.js
// 导入React、useState、useMemo、useCallback、memo
import React, { useState, useMemo, useCallback, memo } from 'react';
// 导入虚拟滚动组件
import VirtualizedList from './VirtualizedList';
// 定义表格单元格组件
// 使用memo优化
const TableCell = memo(function TableCell({ value, type = 'text' }) {
// 根据类型格式化值
const formatValue = (val, valType) => {
switch (valType) {
case 'number':
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(val);
case 'date':
return new Date(val).toLocaleDateString();
case 'status':
return (
<span className={`status status-${val.toLowerCase()}`}>
  {val}
  </span>
    );
    default:
    return val;
    }
    };
    return (
    <td className="table-cell">
      {formatValue(value, type)}
      </td>
        );
        });
        // 定义表格行组件
        // 使用memo优化,自定义比较函数
        const TableRow = memo(function TableRow({
        row,
        columns,
        isSelected,
        onSelect,
        onToggle
        }) {
        // 处理行点击
        const handleRowClick = useCallback(() => {
        onSelect(row.id);
        }, [row.id, onSelect]);
        // 处理复选框点击
        const handleCheckboxClick = useCallback((e) => {
        e.stopPropagation();
        onToggle(row.id);
        }, [row.id, onToggle]);
        return (
        <tr
        className={`table-row ${isSelected ? 'selected' : ''}`}
        onClick={handleRowClick}
        >
        <td className="table-cell">
          <input
          type="checkbox"
          checked={isSelected}
          onChange={handleCheckboxClick}
          />
          </td>
            {columns.map(column => (
            <TableCell
            key={column.key}
            value={row[column.key]}
            type={column.type}
            />
            ))}
            </tr>
              );
              }, (prevProps, nextProps) => {
              // 自定义比较函数
              // 只有当row、isSelected变化时才重新渲染
              return prevProps.row.id === nextProps.row.id &&
              prevProps.isSelected === nextProps.isSelected &&
              JSON.stringify(prevProps.row) === JSON.stringify(nextProps.row);
              });
              // 定义表格头部组件
              // 使用memo优化
              const TableHeader = memo(function TableHeader({
              columns,
              sortColumn,
              sortDirection,
              onSort
              }) {
              // 处理排序
              const handleSort = useCallback((columnKey) => {
              onSort(columnKey);
              }, [onSort]);
              return (
              <thead>
                <tr>
                  <th className="table-header">
                    <input type="checkbox" />
                      </th>
                        {columns.map(column => (
                        <th
                        key={column.key}
                        className="table-header"
                        onClick={() => handleSort(column.key)}
                        >
                        {column.label}
                        {sortColumn === column.key && (
                        <span className="sort-indicator">
                          {sortDirection === 'asc' ? '↑' : '↓'}
                          </span>
                            )}
                            </th>
                              ))}
                              </tr>
                                </thead>
                                  );
                                  });
                                  // 定义优化的数据表格组件
                                  function OptimizedDataTable({ data }) {
                                  // 使用useState Hook管理状态
                                  const [sortColumn, setSortColumn] = useState(null);
                                  const [sortDirection, setSortDirection] = useState('asc');
                                  const [filter, setFilter] = useState('');
                                  const [selectedRows, setSelectedRows] = useState([]);
                                  const [pageSize, setPageSize] = useState(50);
                                  // 定义列配置
                                  const columns = useMemo(() => [
                                  { key: 'name', label: 'Name', type: 'text' },
                                  { key: 'category', label: 'Category', type: 'text' },
                                  { key: 'price', label: 'Price', type: 'number' },
                                  { key: 'status', label: 'Status', type: 'status' },
                                  { key: 'date', label: 'Date', type: 'date' }
                                  ], []);
                                  // 使用useMemo Hook记忆化过滤和排序后的数据
                                  const processedData = useMemo(() => {
                                  let filtered = data;
                                  // 应用过滤器
                                  if (filter.trim()) {
                                  const filterLower = filter.toLowerCase();
                                  filtered = filtered.filter(item =>
                                  Object.values(item).some(value =>
                                  String(value).toLowerCase().includes(filterLower)
                                  )
                                  );
                                  }
                                  // 应用排序
                                  if (sortColumn) {
                                  filtered = [...filtered].sort((a, b) => {
                                  const aValue = a[sortColumn];
                                  const bValue = b[sortColumn];
                                  if (aValue < bValue) return sortDirection === 'asc' ? -1 : 1;
                                  if (aValue > bValue) return sortDirection === 'asc' ? 1 : -1;
                                  return 0;
                                  });
                                  }
                                  return filtered;
                                  }, [data, filter, sortColumn, sortDirection]);
                                  // 使用useCallback Hook记忆化函数
                                  const handleSort = useCallback((columnKey) => {
                                  if (sortColumn === columnKey) {
                                  setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc');
                                  } else {
                                  setSortColumn(columnKey);
                                  setSortDirection('asc');
                                  }
                                  }, [sortColumn]);
                                  // 使用useCallback Hook记忆化函数
                                  const handleSelect = useCallback((rowId) => {
                                  setSelectedRows(prev =>
                                  prev.includes(rowId)
                                  ? prev.filter(id => id !== rowId)
                                  : [...prev, rowId]
                                  );
                                  }, []);
                                  // 使用useCallback Hook记忆化函数
                                  const handleToggle = useCallback((rowId) => {
                                  handleSelect(rowId);
                                  }, [handleSelect]);
                                  // 使用useCallback Hook记忆化函数
                                  const handleFilterChange = useCallback((e) => {
                                  setFilter(e.target.value);
                                  }, []);
                                  return (
                                  <div className="optimized-data-table">
                                    <div className="table-controls">
                                      <input
                                      type="text"
                                      placeholder="Search..."
                                      value={filter}
                                      onChange={handleFilterChange}
                                      className="search-input"
                                      />
                                      <select
                                      value={pageSize}
                                      onChange={(e) => setPageSize(Number(e.target.value))}
                                      className="page-size-select"
                                      >
                                      <option value={25}>25 per page</option>
                                        <option value={50}>50 per page</option>
                                          <option value={100}>100 per page</option>
                                            <option value={200}>200 per page</option>
                                              </select>
                                                <div className="selected-info">
                                                  Selected: {selectedRows.length} / {processedData.length}
                                                  </div>
                                                    </div>
                                                      <div className="table-container">
                                                        <table className="data-table">
                                                          <TableHeader
                                                          columns={columns}
                                                          sortColumn={sortColumn}
                                                          sortDirection={sortDirection}
                                                          onSort={handleSort}
                                                          />
                                                          <tbody>
                                                            {processedData.slice(0, pageSize).map(row => (
                                                            <TableRow
                                                            key={row.id}
                                                            row={row}
                                                            columns={columns}
                                                            isSelected={selectedRows.includes(row.id)}
                                                            onSelect={handleSelect}
                                                            onToggle={handleToggle}
                                                            />
                                                            ))}
                                                            </tbody>
                                                              </table>
                                                                </div>
                                                                  <div className="table-footer">
                                                                    <p>Showing {Math.min(pageSize, processedData.length)} of {processedData.length} items</p>
                                                                      </div>
                                                                        </div>
                                                                          );
                                                                          }
                                                                          // 导出组件
                                                                          export default OptimizedDataTable;
样式文件(详细注释版)
/* src/App.css */
/* 应用主容器样式 */
.App {
min-height: 100vh;
font-family: Arial, sans-serif;
background-color: #f5f5f5;
}
/* 应用头部样式 */
.App-header {
background-color: #333;
color: white;
padding: 2rem;
text-align: center;
}
.App-header h1 {
margin: 0 0 1rem 0;
font-size: 2rem;
}
.App-header p {
margin: 0;
font-size: 1.2rem;
opacity: 0.8;
}
/* 主要内容区域 */
main {
max-width: 1400px;
margin: 0 auto;
padding: 2rem;
}
/* 优化的数据表格样式 */
.optimized-data-table {
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
overflow: hidden;
}
.table-controls {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background-color: #f8f9fa;
border-bottom: 1px solid #dee2e6;
}
.search-input {
flex: 1;
padding: 0.5rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
}
.page-size-select {
padding: 0.5rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
}
.selected-info {
font-weight: bold;
color: #666;
}
.table-container {
max-height: 600px;
overflow-y: auto;
}
.data-table {
width: 100%;
border-collapse: collapse;
}
.table-header {
background-color: #f8f9fa;
padding: 1rem;
text-align: left;
font-weight: bold;
border-bottom: 2px solid #dee2e6;
cursor: pointer;
user-select: none;
position: sticky;
top: 0;
z-index: 10;
}
.table-header:hover {
background-color: #e9ecef;
}
.sort-indicator {
margin-left: 0.5rem;
color: #007bff;
}
.table-row {
border-bottom: 1px solid #dee2e6;
transition: background-color 0.2s;
cursor: pointer;
}
.table-row:hover {
background-color: #f8f9fa;
}
.table-row.selected {
background-color: #e3f2fd;
}
.table-cell {
padding: 1rem;
border-right: 1px solid #f0f0f0;
}
.table-cell:last-child {
border-right: none;
}
.status {
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-size: 0.875rem;
font-weight: 500;
}
.status-active {
background-color: #d4edda;
color: #155724;
}
.status-inactive {
background-color: #f8d7da;
color: #721c24;
}
.status-pending {
background-color: #fff3cd;
color: #856404;
}
.table-footer {
padding: 1rem;
background-color: #f8f9fa;
border-top: 1px solid #dee2e6;
text-align: center;
color: #666;
}
/* 虚拟滚动样式 */
.virtualized-list {
border: 1px solid #dee2e6;
border-radius: 4px;
}
/* 懒加载图片样式 */
.lazy-image-container {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.lazy-image-placeholder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.lazy-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.lazy-image.loaded {
opacity: 1;
}
.image-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
padding: 1rem;
}
.grid-image {
width: 100%;
height: 200px;
border-radius: 8px;
overflow: hidden;
}
/* 加载状态样式 */
.loading-fallback,
.page-loader {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 2rem;
min-height: 200px;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #007bff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 响应式设计 */
@media (max-width: 768px) {
.table-controls {
flex-direction: column;
align-items: stretch;
}
.search-input {
width: 100%;
}
.table-container {
overflow-x: auto;
}
.data-table {
min-width: 600px;
}
}

练习题目

基础练习

  1. 性能优化基础练习
// 练习1:创建一个使用memo优化的组件
// 实现:父子组件通信,使用memo防止不必要的重新渲染
// 包含:性能监控、渲染次数统计
// 练习2:实现useMemo和useCallback优化
// 实现:昂贵的计算和函数记忆化
// 包含:性能对比、优化前后差异
  1. 渲染优化练习
// 练习3:实现虚拟滚动列表
// 实现:处理大量数据的高性能列表
// 包含:虚拟滚动、懒加载、性能监控
// 练习4:实现图片懒加载
// 实现:IntersectionObserver API、占位符、加载状态
// 包含:性能优化、用户体验提升

进阶练习

  1. 内存管理练习
// 练习5:实现完整的内存管理
// 实现:事件监听器清理、定时器清理、订阅清理
// 包含:内存泄漏检测、性能分析
// 练习6:构建高性能数据表格
// 实现:虚拟滚动、排序、过滤、分页
// 包含:性能优化、用户体验优化
  1. 综合应用练习
// 练习7:优化现有React应用
// 实现:识别性能问题、应用优化技巧
// 包含:性能分析、优化报告、最佳实践