ReactNativeWeb性能优化Skill react-native-web-performance

这个技能专注于优化React Native Web应用的性能,通过代码分割、包优化、内存化和Web特定改进,提升应用加载速度、渲染效率和用户体验。适用于前端开发和跨平台移动开发场景。关键词:React Native Web, 性能优化, 代码分割, 包优化, 内存化, Web优化, 前端开发, 移动开发。

前端开发 0 次安装 0 次浏览 更新于 3/25/2026

名称: react-native-web-performance 用户可调用: 否 描述: 使用于优化React Native Web性能时。提供代码分割、包优化、内存化和Web特定性能改进的模式。 允许工具:

  • 读取
  • 写入
  • 编辑
  • Bash
  • Grep
  • Glob

React Native Web - 性能

React Native Web的性能优化模式,专注于包大小、渲染性能和Web特定优化。

关键概念

代码分割

使用动态导入进行懒加载:

import React, { lazy, Suspense } from 'react';
import { View, ActivityIndicator } from 'react-native';

const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<ActivityIndicator />}>
      <HeavyComponent />
    </Suspense>
  );
}

内存化

使用React.memo和钩子防止不必要的重新渲染:

import React, { memo, useMemo, useCallback } from 'react';

interface Props {
  items: Item[];
  onItemPress: (id: string) => void;
}

export const ItemList = memo(function ItemList({ items, onItemPress }: Props) {
  const sortedItems = useMemo(
    () => items.sort((a, b) => a.name.localeCompare(b.name)),
    [items]
  );

  const handlePress = useCallback(
    (id: string) => {
      onItemPress(id);
    },
    [onItemPress]
  );

  return (
    <View>
      {sortedItems.map(item => (
        <Item key={item.id} item={item} onPress={handlePress} />
      ))}
    </View>
  );
});

用于大型列表的FlatList

使用FlatList高效渲染长列表:

import { FlatList, View, Text } from 'react-native';

interface Item {
  id: string;
  title: string;
}

function ItemsList({ items }: { items: Item[] }) {
  return (
    <FlatList
      data={items}
      keyExtractor={item => item.id}
      renderItem={({ item }) => (
        <View>
          <Text>{item.title}</Text>
        </View>
      )}
      initialNumToRender={10}
      maxToRenderPerBatch={10}
      windowSize={5}
      removeClippedSubviews
    />
  );
}

最佳实践

优化图像

✅ 使用优化的图像格式和懒加载:

import { Image } from 'react-native';

function OptimizedImage({ uri }: { uri: string }) {
  return (
    <Image
      source={{ uri }}
      style={{ width: 200, height: 200 }}
      resizeMode="cover"
      // Web特定:懒加载
      {...(Platform.OS === 'web' && {
        loading: 'lazy',
      })}
    />
  );
}

避免内联函数

✅ 使用useCallback处理事件处理器:

import { useCallback } from 'react';

function Component({ onSave }: { onSave: (data: Data) => void }) {
  const [data, setData] = useState<Data>();

  const handleSave = useCallback(() => {
    if (data) {
      onSave(data);
    }
  }, [data, onSave]);

  return <Button onPress={handleSave} title="保存" />;
}

优化StyleSheet

✅ 在组件外部创建StyleSheet:

import { StyleSheet } from 'react-native';

// 好 - 创建一次
const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 16,
  },
});

function Component() {
  return <View style={styles.container} />;
}

// 坏 - 每次渲染重新创建
function BadComponent() {
  const styles = StyleSheet.create({
    container: { flex: 1 },
  });
  return <View style={styles.container} />;
}

示例

带优化的虚拟化列表

import React, { useCallback, memo } from 'react';
import { FlatList, View, Text, StyleSheet } from 'react-native';

interface Item {
  id: string;
  title: string;
  description: string;
}

interface ItemCardProps {
  item: Item;
  onPress: (id: string) => void;
}

const ItemCard = memo(function ItemCard({ item, onPress }: ItemCardProps) {
  const handlePress = useCallback(() => {
    onPress(item.id);
  }, [item.id, onPress]);

  return (
    <Pressable onPress={handlePress}>
      <View style={styles.card}>
        <Text style={styles.title}>{item.title}</Text>
        <Text style={styles.description}>{item.description}</Text>
      </View>
    </Pressable>
  );
});

export function OptimizedList({ items, onItemPress }: {
  items: Item[];
  onItemPress: (id: string) => void;
}) {
  const renderItem = useCallback(
    ({ item }: { item: Item }) => (
      <ItemCard item={item} onPress={onItemPress} />
    ),
    [onItemPress]
  );

  const keyExtractor = useCallback((item: Item) => item.id, []);

  return (
    <FlatList
      data={items}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      initialNumToRender={10}
      maxToRenderPerBatch={10}
      windowSize={5}
      removeClippedSubviews
      getItemLayout={(data, index) => ({
        length: 80,
        offset: 80 * index,
        index,
      })}
    />
  );
}

const styles = StyleSheet.create({
  card: {
    padding: 16,
    backgroundColor: '#fff',
    marginBottom: 8,
    borderRadius: 8,
  },
  title: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 4,
  },
  description: {
    fontSize: 14,
    color: '#666',
  },
});

动态导入

import React, { lazy, Suspense, useState } from 'react';
import { View, Button, ActivityIndicator } from 'react-native';

// 懒加载重型组件
const Chart = lazy(() => import('./Chart'));
const DataTable = lazy(() => import('./DataTable'));

export function Dashboard() {
  const [showChart, setShowChart] = useState(false);

  return (
    <View>
      <Button
        title="显示图表"
        onPress={() => setShowChart(true)}
      />

      {showChart && (
        <Suspense fallback={<ActivityIndicator />}>
          <Chart />
        </Suspense>
      )}
    </View>
  );
}

优化上下文

import React, { createContext, useContext, useMemo, ReactNode } from 'react';

interface User {
  id: string;
  name: string;
}

interface UserContextValue {
  user: User | null;
  isLoading: boolean;
}

const UserContext = createContext<UserContextValue | undefined>(undefined);

export function UserProvider({
  user,
  isLoading,
  children,
}: {
  user: User | null;
  isLoading: boolean;
  children: ReactNode;
}) {
  // 内存化上下文值以防止不必要的重新渲染
  const value = useMemo(
    () => ({ user, isLoading }),
    [user, isLoading]
  );

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

export function useUser() {
  const context = useContext(UserContext);
  if (context === undefined) {
    throw new Error('useUser必须在UserProvider内使用');
  }
  return context;
}

常见模式

防抖输入

import { useState, useEffect } from 'react';
import { TextInput } from 'react-native';

function SearchInput({ onSearch }: { onSearch: (query: string) => void }) {
  const [query, setQuery] = useState('');

  useEffect(() => {
    const timer = setTimeout(() => {
      onSearch(query);
    }, 300);

    return () => clearTimeout(timer);
  }, [query, onSearch]);

  return (
    <TextInput
      value={query}
      onChangeText={setQuery}
      placeholder="搜索..."
    />
  );
}

交叉观察器(Web)

import { useEffect, useRef, useState } from 'react';
import { View, Platform } from 'react-native';

function LazyLoadComponent({ children }: { children: React.ReactNode }) {
  const [isVisible, setIsVisible] = useState(false);
  const ref = useRef<View>(null);

  useEffect(() => {
    if (Platform.OS !== 'web') {
      setIsVisible(true);
      return;
    }

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

    const element = ref.current as any;
    if (element) {
      observer.observe(element);
    }

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

  return (
    <View ref={ref}>
      {isVisible ? children : <View style={{ height: 200 }} />}
    </View>
  );
}

包大小优化

// webpack.config.js 或 metro.config.js
module.exports = {
  resolve: {
    alias: {
      // 使用轻量级替代
      'react-native$': 'react-native-web',
      'lodash': 'lodash-es',
    },
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
        },
      },
    },
  },
};

反模式

❌ 不要在渲染内创建StyleSheet:

// 坏
function Component() {
  const styles = StyleSheet.create({ container: { flex: 1 } });
  return <View style={styles.container} />;
}

// 好
const styles = StyleSheet.create({ container: { flex: 1 } });
function Component() {
  return <View style={styles.container} />;
}

❌ 不要在FlatList中使用内联函数:

// 坏
<FlatList
  data={items}
  renderItem={({ item }) => <Item item={item} onPress={() => handlePress(item.id)} />}
/>

// 好
const renderItem = useCallback(({ item }) => (
  <Item item={item} onPress={handlePress} />
), [handlePress]);

<FlatList data={items} renderItem={renderItem} />

❌ 不要导入整个库:

// 坏
import _ from 'lodash';

// 好
import debounce from 'lodash/debounce';

❌ 不要在长列表中渲染所有项:

// 坏
{items.map(item => <Item key={item.id} item={item} />)}

// 好
<FlatList
  data={items}
  renderItem={({ item }) => <Item item={item} />}
/>

相关技能

  • react-native-web-core: React Native Web核心概念
  • react-native-web-styling: 优化样式模式
  • react-native-web-testing: 性能测试策略