React性能优化是构建高质量Web应用的关键。随着应用规模的增长,性能问题会逐渐显现。本文将全面介绍React性能优化的各种技巧和最佳实践。

1. 组件优化基础

React.memo优化函数组件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 普通组件 - 每次父组件更新都会重新渲染
const UserProfile = ({ name, age, avatar }) => {
    console.log('UserProfile re-rendered');
    return (
        <div className="user-profile">
            <img src={avatar} alt={name} />
            <div>
                <h2>{name}</h2>
                <p>Age: {age}</p>
            </div>
        </div>
    );
};

// 优化后 - 只有props变化时才重新渲染
const OptimizedUserProfile = React.memo(({ name, age, avatar }) => {
    console.log('OptimizedUserProfile re-rendered');
    return (
        <div className="user-profile">
            <img src={avatar} alt={name} />
            <div>
                <h2>{name}</h2>
                <p>Age: {age}</p>
            </div>
        </div>
    );
});

// 自定义比较函数
const CustomUserProfile = React.memo(({ user }) => {
    return (
        <div className="user-profile">
            <h2>{user.name}</h2>
            <p>{user.email}</p>
        </div>
    );
}, (prevProps, nextProps) => {
    // 只有ID或基本信息变化时才重新渲染
    return prevProps.user.id === nextProps.user.id &&
           prevProps.user.name === nextProps.user.name &&
           prevProps.user.email === nextProps.user.email;
});

useMemo缓存计算结果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const ExpensiveComponent = ({ items, filter }) => {
    // ❌ 每次渲染都会重新计算
    const filteredItems = items.filter(item =>
        item.name.toLowerCase().includes(filter.toLowerCase())
    );

    // ✅ 使用useMemo缓存计算结果
    const expensiveValue = useMemo(() => {
        console.log('Expensive calculation running...');
        return items
            .filter(item => item.price > 100)
            .reduce((sum, item) => sum + item.price, 0);
    }, [items]);

    // 更复杂的计算示例
    const chartData = useMemo(() => {
        const data = items.map(item => ({
            name: item.name,
            value: calculateComplexMetrics(item),
            category: categorizeItem(item)
        }));

        return processDataForChart(data);
    }, [items]);

    return (
        <div>
            <h3>Total Value: ${expensiveValue}</h3>
            <Chart data={chartData} />
        </div>
    );
};

useCallback缓存函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const ParentComponent = ({ items }) => {
    const [selectedItem, setSelectedItem] = useState(null);

    // ❌ 每次渲染都创建新函数
    const handleSelect = (item) => {
        setSelectedItem(item);
    };

    // ✅ 使用useMemo缓存计算
    const expensiveValue = useMemo(() => {
        return items.reduce((sum, item) => sum + item.value, 0);
    }, [items]);

    // ✅ 使用useCallback缓存函数
    const handleSelect = useCallback((item) => {
        setSelectedItem(item);
        // 依赖项为空数组,函数内部不依赖外部变量
    }, []);

    // ✅ 函数依赖外部变量
    const handleAction = useCallback((itemId) => {
        const item = items.find(i => i.id === itemId);
        if (item) {
            setSelectedItem(item);
        }
    }, [items]);

    return (
        <div>
            <p>Total: {expensiveValue}</p>
            <ItemList
                items={items}
                onSelect={handleSelect}
                onAction={handleAction}
                selectedItem={selectedItem}
            />
        </div>
    );
};

2. 状态管理优化

避免不必要的状态提升

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// ❌ 错误的状态管理
const BadExample = () => {
    const [formData, setFormData] = useState({
        name: '',
        email: '',
        password: '',
        confirmPassword: ''
    });

    const handleInputChange = (field) => (e) => {
        setFormData(prev => ({
            ...prev,
            [field]: e.target.value
        }));
    };

    return (
        <form>
            <input
                value={formData.name}
                onChange={handleInputChange('name')}
                placeholder="Name"
            />
            <input
                value={formData.email}
                onChange={handleInputChange('email')}
                placeholder="Email"
            />
            <input
                value={formData.password}
                onChange={handleInputChange('password')}
                type="password"
                placeholder="Password"
            />
        </form>
    );
};

// ✅ 优化后的状态管理
const GoodExample = () => {
    // 将相关的状态分组
    const [user, setUser] = useState({ name: '', email: '' });
    const [password, setPassword] = useState('');
    const [confirmPassword, setConfirmPassword] = useState('');

    // 使用reducer管理复杂状态
    const [formData, dispatch] = useReducer(formReducer, initialFormState);

    // 使用useReducer管理表单状态
    const formReducer = (state, action) => {
        switch (action.type) {
            case 'SET_FIELD':
                return {
                    ...state,
                    [action.field]: action.value
                };
            case 'RESET_FORM':
                return initialFormState;
            default:
                return state;
        }
    };

    const handleInputChange = (field) => (e) => {
        dispatch({
            type: 'SET_FIELD',
            field,
            value: e.target.value
        });
    };

    return (
        <form>
            <input
                value={formData.name}
                onChange={handleInputChange('name')}
                placeholder="Name"
            />
            <input
                value={formData.email}
                onChange={handleInputChange('email')}
                placeholder="Email"
            />
        </form>
    );
};

状态分离和组合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// ✅ 状态分离
const UserDashboard = ({ userId }) => {
    // 用户信息状态
    const [user, setUser] = useState(null);
    const [userLoading, setUserLoading] = useState(false);

    // 文章列表状态
    const [articles, setArticles] = useState([]);
    const [articleLoading, setArticleLoading] = useState(false);

    // 设置状态状态
    const [settings, setSettings] = useState({});
    const [settingsLoading, setSettingsLoading] = useState(false);

    // 自定义Hook管理相关状态
    const { user, loading: userLoading } = useUser(userId);
    const { articles, loading: articleLoading } = useUserArticles(userId);
    const { settings, loading: settingsLoading } = useSettings();

    return (
        <div>
            {userLoading ? <UserSkeleton /> : <UserProfile user={user} />}
            {articleLoading ? <ArticleSkeleton /> : <ArticleList articles={articles} />}
            {settingsLoading ? <SettingsSkeleton /> : <SettingsPanel settings={settings} />}
        </div>
    );
};

// 自定义Hook示例
const useUserArticles = (userId) => {
    const [articles, setArticles] = useState([]);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);

    useEffect(() => {
        if (!userId) return;

        setLoading(true);
        fetchUserArticles(userId)
            .then(setArticles)
            .catch(setError)
            .finally(() => setLoading(false));
    }, [userId]);

    return { articles, loading, error };
};

Context优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// ❌ 未优化的Context - 会导致所有消费者重新渲染
const BadContext = React.createContext();

const BadProvider = ({ children }) => {
    const [user, setUser] = useState(null);
    const [theme, setTheme] = useState('light');
    const [notifications, setNotifications] = useState([]);

    // 任何状态变化都会导致所有消费者重新渲染
    const value = {
        user,
        setUser,
        theme,
        setTheme,
        notifications,
        setNotifications
    };

    return (
        <BadContext.Provider value={value}>
            {children}
        </BadContext.Provider>
    );
};

// ✅ 优化后的Context - 分离不同关注点
const UserContext = React.createContext();
const ThemeContext = React.createContext();
const NotificationContext = React.createContext();

const UserProvider = ({ children }) => {
    const [user, setUser] = useState(null);

    // 使用memo防止不必要的重新渲染
    const value = useMemo(() => ({
        user,
        setUser
    }), [user]);

    return (
        <UserContext.Provider value={value}>
            {children}
        </UserContext.Provider>
    );
};

// 使用Context选择器模式
const useUser = () => {
    const context = useContext(UserContext);
    if (!context) {
        throw new Error('useUser must be used within UserProvider');
    }
    return context;
};

const useUserName = () => {
    const { user } = useUser();
    return user?.name;
};

3. 渲染优化

虚拟列表实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import { FixedSizeList as List } from 'react-window';

// 虚拟化长列表
const VirtualizedList = ({ items }) => {
    const Row = ({ index, style }) => (
        <div style={style}>
            <ListItem item={items[index]} />
        </div>
    );

    return (
        <List
            height={600}
            itemCount={items.length}
            itemSize={80}
            width="100%"
        >
            {Row}
        </List>
    );
};

// 自定义虚拟化组件
const CustomVirtualList = ({ items, itemHeight = 50, containerHeight = 400 }) => {
    const [scrollTop, setScrollTop] = useState(0);
    const containerRef = useRef(null);

    const visibleStart = Math.floor(scrollTop / itemHeight);
    const visibleEnd = Math.min(
        visibleStart + Math.ceil(containerHeight / itemHeight) + 1,
        items.length
    );

    const visibleItems = items.slice(visibleStart, visibleEnd);

    const handleScroll = useCallback((e) => {
        setScrollTop(e.target.scrollTop);
    }, []);

    return (
        <div
            ref={containerRef}
            style={{ height: containerHeight, overflow: 'auto' }}
            onScroll={handleScroll}
        >
            <div style={{ height: items.length * itemHeight, position: 'relative' }}>
                {visibleItems.map((item, index) => (
                    <div
                        key={visibleStart + index}
                        style={{
                            position: 'absolute',
                            top: (visibleStart + index) * itemHeight,
                            height: itemHeight,
                            width: '100%'
                        }}
                    >
                        <ListItem item={item} />
                    </div>
                ))}
            </div>
        </div>
    );
};

懒加载和代码分割

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import { lazy, Suspense } from 'react';

// 路由级别的代码分割
const HomePage = lazy(() => import('./pages/HomePage'));
const AboutPage = lazy(() => import('./pages/AboutPage'));
const ContactPage = lazy(() => import('./pages/ContactPage'));

const App = () => (
    <Router>
        <Suspense fallback={<div>Loading...</div>}>
            <Routes>
                <Route path="/" element={<HomePage />} />
                <Route path="/about" element={<AboutPage />} />
                <Route path="/contact" element={<ContactPage />} />
            </Routes>
        </Suspense>
    </Router>
);

// 组件级别的懒加载
const LazyChart = lazy(() =>
    import('./components/Chart').then(module => ({
        default: module.Chart
    }))
);

const Dashboard = ({ data }) => (
    <div>
        <h2>Dashboard</h2>
        <Suspense fallback={<div>Loading chart...</div>}>
            <LazyChart data={data} />
        </Suspense>
    </div>
);

// 动态导入工具函数
const loadComponent = (importFunc, fallback = null) => {
    const LazyComponent = lazy(importFunc);

    return (props) => (
        <Suspense fallback={fallback || <div>Loading...</div>}>
            <LazyComponent {...props} />
        );
    };

// 使用示例
const AsyncAdminPanel = loadComponent(
    () => import('./AdminPanel'),
    <div>Loading admin panel...</div>
);

图片优化和懒加载

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { useState, useRef, useEffect } from 'react';

const LazyImage = ({ src, alt, placeholder, className }) => {
    const [isLoaded, setIsLoaded] = useState(false);
    const [isInView, setIsInView] = useState(false);
    const imgRef = useRef();

    useEffect(() => {
        const observer = new IntersectionObserver(
            ([entry]) => {
                if (entry.isIntersecting) {
                    setIsInView(true);
                    observer.disconnect();
                }
            },
            { threshold: 0.1 }
        );

        if (imgRef.current) {
            observer.observe(imgRef.current);
        }

        return () => observer.disconnect();
    }, []);

    const handleLoad = () => {
        setIsLoaded(true);
    };

    return (
        <div ref={imgRef} className={className}>
            {isInView && (
                <img
                    src={src}
                    alt={alt}
                    onLoad={handleLoad}
                    style={{
                        opacity: isLoaded ? 1 : 0,
                        transition: 'opacity 0.3s ease'
                    }}
                />
            )}
            {!isLoaded && (
                <div
                    className="image-placeholder"
                    style={{
                        backgroundColor: '#f0f0f0',
                        backgroundImage: placeholder ? `url(${placeholder})` : 'none',
                        backgroundSize: 'cover',
                        backgroundPosition: 'center'
                    }}
                />
            )}
        </div>
    );
};

// 响应式图片组件
const ResponsiveImage = ({ sources, alt, className }) => {
    const [loadedSources, setLoadedSources] = useState(new Set());

    const handleSourceLoad = (src) => {
        setLoadedSources(prev => new Set(prev).add(src));
    };

    return (
        <picture className={className}>
            {sources.map(({ srcSet, media, type }) => (
                <source
                    key={srcSet}
                    srcSet={srcSet}
                    media={media}
                    type={type}
                    onLoad={() => handleSourceLoad(srcSet)}
                />
            ))}
            <img
                src={sources[sources.length - 1].fallback}
                alt={alt}
                loading="lazy"
            />
        </picture>
    );
};

4. Bundle优化

动态导入和Tree Shaking

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// utils.js
export const heavyFunction = () => {
    // 复杂的计算逻辑
    console.log('This is a heavy function');
};

export const lightFunction = () => {
    // 简单的逻辑
    console.log('This is a light function');
};

export default {
    heavyFunction,
    lightFunction
};

// 使用动态导入
const loadHeavyModule = async () => {
    const { heavyFunction } = await import('./utils');
    heavyFunction();
};

// 条件导入
const useFeature = (featureEnabled) => {
    const [module, setModule] = useState(null);

    useEffect(() => {
        if (featureEnabled) {
            import('./heavyFeature').then(setModule);
        }
    }, [featureEnabled]);

    return module;
};

// Webpack魔法注释
const loadModuleByLanguage = (language) => {
    switch (language) {
        case 'en':
            return import(/* webpackChunkName: "lang-en" */ './locales/en.json');
        case 'zh':
            return import(/* webpackChunkName: "lang-zh" */ './locales/zh.json');
        default:
            return import(/* webpackChunkName: "lang-en" */ './locales/en.json');
    }
};

Bundle分析和优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// webpack.config.js
module.exports = {
    optimization: {
        splitChunks: {
            chunks: 'all',
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendors',
                    chunks: 'all',
                },
                common: {
                    name: 'common',
                    minChunks: 2,
                    chunks: 'all',
                    enforce: true
                },
                components: {
                    test: /[\\/]src[\\/]components[\\/]/,
                    name: 'components',
                    chunks: 'all',
                    minSize: 0
                }
            }
        }
    }
};

// 使用webpack-bundle-analyzer分析Bundle
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
    plugins: [
        new BundleAnalyzerPlugin({
            analyzerMode: 'static',
            openAnalyzer: false
        })
    ]
};

5. 性能监控

性能测量工具

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import { useProfiler, unstable_trace as trace } from 'react';

// React Profiler API
const ProfiledComponent = ({ id, onRender, ...props }) => {
    return (
        <Profiler id={id} onRender={onRender}>
            <ExpensiveComponent {...props} />
        </Profiler>
    );
};

const App = () => {
    const handleRender = (id, phase, actualDuration) => {
        console.log(`${id} ${phase} took ${actualDuration}ms`);
    };

    return (
        <div>
            <ProfiledComponent id="UserProfile" onRender={handleRender}>
                <UserProfile user={user} />
            </ProfiledComponent>
        </div>
    );
};

// 自定义性能Hook
const usePerformanceMeasure = (name) => {
    useEffect(() => {
        const startTime = performance.now();

        return () => {
            const endTime = performance.now();
            console.log(`${name} took ${endTime - startTime}ms`);
        };
    }, [name]);
};

// 使用示例
const ExpensiveComponent = ({ data }) => {
    usePerformanceMeasure('ExpensiveComponent');

    const processedData = useMemo(() => {
        return expensiveDataProcessing(data);
    }, [data]);

    return <div>{/* 组件内容 */}</div>;
};

Web Vitals监控

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 使用web-vitals库
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';

const reportWebVitals = (onPerfEntry) => {
    if (onPerfEntry && onPerfEntry instanceof Function) {
        import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
            getCLS(onPerfEntry);
            getFID(onPerfEntry);
            getFCP(onPerfEntry);
            getLCP(onPerfEntry);
            getTTFB(onPerfEntry);
        });
    }
};

// 在应用中使用
const App = () => {
    useEffect(() => {
        reportWebVitals(console.log);

        // 或者发送到分析服务
        reportWebVitals((metric) => {
            analytics.track('Web Vitals', {
                name: metric.name,
                value: metric.value,
                id: metric.id,
                delta: metric.delta,
            });
        });
    }, []);

    return <div> {/* 应用内容 */} </div>;
};

6. 高级优化技巧

渲染批次调度

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { unstable_batchedUpdates } from 'react-dom';

// 批量更新状态
const batchUpdateExample = () => {
    // 这些更新会被批量处理,只触发一次重新渲染
    unstable_batchedUpdates(() => {
        setCount(prev => prev + 1);
        setName('New Name');
        setAge(25);
    });
};

// 在事件处理器中自动批量更新(React 18+)
const handleClick = () => {
    // React 18中这些更新会自动批量处理
    setCount(prev => prev + 1);
    setName('New Name');
    setAge(25);
};

// 异步操作中的批量更新
const fetchData = async () => {
    const response = await fetch('/api/data');
    const data = await response.json();

    // 批量更新状态
    unstable_batchedUpdates(() => {
        setData(data);
        setLoading(false);
        setError(null);
    });
};

Concurrent Mode和Suspense

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { Suspense, startTransition } from 'react';

const SearchResults = ({ query }) => {
    const [results, setResults] = useState([]);
    const [isPending, startTransition] = useTransition();

    const handleSearch = (searchQuery) => {
        // 标记更新为过渡
        startTransition(() => {
            // 非紧急更新
            setResults(searchData(searchQuery));
        });

        // 紧急更新
        setSearchQuery(searchQuery);
    };

    return (
        <div>
            <input
                type="text"
                onChange={(e) => handleSearch(e.target.value)}
                placeholder="Search..."
            />

            {isPending && <div>Searching...</div>}

            <Suspense fallback={<div>Loading results...</div>}>
                <ResultsList results={results} />
            </Suspense>
        </div>
    );
};

// 数据获取组件
const DataFetcher = ({ url }) => {
    const [data, setData] = useState(null);

    useEffect(() => {
        let isMounted = true;

        fetchData(url).then(response => {
            if (isMounted) {
                setData(response);
            }
        });

        return () => {
            isMounted = false;
        };
    }, [url]);

    if (!data) {
        throw new Promise(resolve => {
            setTimeout(() => resolve(fetchData(url)), 1000);
        });
    }

    return <div>{/* 渲染数据 */}</div>;
};

7. 实战案例

电商产品列表优化

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
const ProductList = ({ products, filters, sortBy }) => {
    // 使用useMemo缓存过滤和排序结果
    const filteredAndSortedProducts = useMemo(() => {
        let result = [...products];

        // 应用过滤器
        if (filters.category) {
            result = result.filter(p => p.category === filters.category);
        }

        if (filters.minPrice) {
            result = result.filter(p => p.price >= filters.minPrice);
        }

        if (filters.maxPrice) {
            result = result.filter(p => p.price <= filters.maxPrice);
        }

        // 应用排序
        result.sort((a, b) => {
            switch (sortBy) {
                case 'price-low':
                    return a.price - b.price;
                case 'price-high':
                    return b.price - a.price;
                case 'name':
                    return a.name.localeCompare(b.name);
                default:
                    return 0;
            }
        });

        return result;
    }, [products, filters, sortBy]);

    // 虚拟化长列表
    const Row = React.memo(({ index, style }) => (
        <div style={style}>
            <ProductCard product={filteredAndSortedProducts[index]} />
        </div>
    ));

    return (
        <div>
            <div className="filters">
                <ProductFilters
                    filters={filters}
                    onChange={setFilters}
                />
            </div>

            <div className="results-count">
                Showing {filteredAndSortedProducts.length} products
            </div>

            <List
                height={600}
                itemCount={filteredAndSortedProducts.length}
                itemSize={200}
                width="100%"
            >
                {Row}
            </List>
        </div>
    );
};

// 优化的产品卡片组件
const ProductCard = React.memo(({ product }) => {
    const [isImageLoaded, setIsImageLoaded] = useState(false);
    const [isInView, setIsInView] = useState(false);
    const imgRef = useRef();

    useEffect(() => {
        const observer = new IntersectionObserver(
            ([entry]) => setIsInView(entry.isIntersecting),
            { threshold: 0.1 }
        );

        if (imgRef.current) {
            observer.observe(imgRef.current);
        }

        return () => observer.disconnect();
    }, []);

    return (
        <div className="product-card">
            <div ref={imgRef} className="product-image">
                {isInView && (
                    <img
                        src={product.imageUrl}
                        alt={product.name}
                        onLoad={() => setIsImageLoaded(true)}
                        style={{ opacity: isImageLoaded ? 1 : 0 }}
                    />
                )}
            </div>
            <h3>{product.name}</h3>
            <p className="price">${product.price}</p>
            <button
                onClick={() => addToCart(product)}
                className="add-to-cart"
            >
                Add to Cart
            </button>
        </div>
    );
});

总结

React性能优化需要从多个层面考虑:

组件级优化:

  • 使用React.memo、useMemo、useCallback
  • 避免不必要的重新渲染
  • 合理拆分组件

状态管理优化:

  • 避免状态过度提升
  • 使用Context分离关注点
  • 合理使用本地状态和全局状态

渲染优化:

  • 虚拟化长列表
  • 懒加载和代码分割
  • 图片优化

构建优化:

  • 代码分割和Tree Shaking
  • Bundle分析和优化
  • 资源压缩和缓存

记住,性能优化应该基于实际测量,过早优化是万恶之源。使用React DevTools Profiler、Web Vitals等工具识别性能瓶颈,然后有针对性地进行优化。