React Native性能优化 #

概述 #

性能优化是移动应用开发的重要环节。本章节介绍 React Native 应用的性能优化技巧。

渲染优化 #

React.memo #

防止不必要的重新渲染:

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

interface ItemProps {
  id: string;
  title: string;
  onPress: (id: string) => void;
}

const ListItem: React.FC<ItemProps> = React.memo(({id, title, onPress}) => {
  console.log('Rendering item:', id);
  
  return (
    <TouchableOpacity onPress={() => onPress(id)}>
      <Text>{title}</Text>
    </TouchableOpacity>
  );
}, (prevProps, nextProps) => {
  return prevProps.id === nextProps.id && prevProps.title === nextProps.title;
});

export default ListItem;

useMemo #

缓存计算结果:

tsx
import React, {useMemo} from 'react';

const ExpensiveComponent = ({items}) => {
  const sortedItems = useMemo(() => {
    console.log('Sorting items...');
    return [...items].sort((a, b) => a.name.localeCompare(b.name));
  }, [items]);

  const totalPrice = useMemo(() => {
    return items.reduce((sum, item) => sum + item.price, 0);
  }, [items]);

  return (
    <View>
      <Text>Total: ${totalPrice}</Text>
      {sortedItems.map(item => (
        <Item key={item.id} item={item} />
      ))}
    </View>
  );
};

useCallback #

缓存回调函数:

tsx
import React, {useCallback} from 'react';

const ParentComponent = ({items}) => {
  const handleItemPress = useCallback((id: string) => {
    console.log('Item pressed:', id);
  }, []);

  const handleItemDelete = useCallback((id: string) => {
    setItems(prev => prev.filter(item => item.id !== id));
  }, []);

  return (
    <FlatList
      data={items}
      renderItem={({item}) => (
        <ListItem
          item={item}
          onPress={handleItemPress}
          onDelete={handleItemDelete}
        />
      )}
      keyExtractor={item => item.id}
    />
  );
};

列表优化 #

FlatList 配置 #

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

const OptimizedList = ({data}) => {
  const renderItem = useCallback(({item}) => (
    <Item item={item} />
  ), []);

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

  const getItemLayout = useCallback((data, index) => ({
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * index,
    index,
  }), []);

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      getItemLayout={getItemLayout}
      initialNumToRender={10}
      maxToRenderPerBatch={10}
      windowSize={5}
      removeClippedSubviews={true}
      updateCellsBatchingPeriod={50}
      ListEmptyComponent={<EmptyComponent />}
      ListFooterComponent={<FooterComponent />}
      ItemSeparatorComponent={ItemSeparator}
    />
  );
};

FlatList 配置说明 #

属性 说明 推荐值
initialNumToRender 初始渲染数量 10-20
maxToRenderPerBatch 每批渲染数量 10
windowSize 渲染窗口大小 5-10
removeClippedSubviews 移除不可见视图 true
updateCellsBatchingPeriod 批量更新间隔 50ms
getItemLayout 固定高度优化 必须设置

虚拟化列表 #

tsx
const VirtualizedListExample = () => {
  const getItem = (data, index) => ({
    id: data[index].id,
    title: data[index].title,
  });

  const getItemCount = (data) => data.length;

  return (
    <VirtualizedList
      data={data}
      getItem={getItem}
      getItemCount={getItemCount}
      renderItem={renderItem}
      keyExtractor={item => item.id}
    />
  );
};

图片优化 #

图片缓存 #

tsx
import React from 'react';
import {Image} from 'react-native';

const CachedImage = ({uri, style}) => {
  return (
    <Image
      source={{
        uri,
        cache: 'only-if-cached',
      }}
      style={style}
      resizeMode="cover"
    />
  );
};

图片预加载 #

tsx
import {Image} from 'react-native';

const preloadImages = (urls: string[]) => {
  urls.forEach(url => {
    Image.prefetch(url);
  });
};

// 使用
preloadImages([
  'https://example.com/image1.jpg',
  'https://example.com/image2.jpg',
]);

图片尺寸优化 #

tsx
const OptimizedImage = ({uri, width}) => {
  const [height, setHeight] = useState(200);

  useEffect(() => {
    Image.getSize(uri, (w, h) => {
      const ratio = width / w;
      setHeight(h * ratio);
    });
  }, [uri, width]);

  return (
    <Image
      source={{uri}}
      style={{width, height}}
      resizeMode="cover"
    />
  );
};

内存优化 #

清理副作用 #

tsx
import React, {useEffect, useState} from 'react';

const DataFetcher = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    let isMounted = true;
    let timer: NodeJS.Timeout;

    const fetchData = async () => {
      const result = await api.getData();
      if (isMounted) {
        setData(result);
      }
    };

    fetchData();

    timer = setInterval(() => {
      fetchData();
    }, 30000);

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

  return <DataList data={data} />;
};

避免内存泄漏 #

tsx
const useAbortableFetch = (url: string) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const controller = new AbortController();

    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch(url, {
          signal: controller.signal,
        });
        const json = await response.json();
        setData(json);
      } catch (err) {
        if (err.name !== 'AbortError') {
          setError(err);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => {
      controller.abort();
    };
  }, [url]);

  return {data, loading, error};
};

JavaScript 线程优化 #

InteractionManager #

在交互完成后执行任务:

tsx
import {InteractionManager} from 'react-native';

const HeavyComponent = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    const task = InteractionManager.runAfterInteractions(() => {
      const result = heavyComputation();
      setData(result);
    });

    return () => task.cancel();
  }, []);

  return <View>{data && <DataDisplay data={data} />}</View>;
};

延迟加载 #

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

const App = () => {
  const [showHeavy, setShowHeavy] = useState(false);

  return (
    <View>
      <Button title="Load Heavy" onPress={() => setShowHeavy(true)} />
      {showHeavy && (
        <React.Suspense fallback={<Loading />}>
          <LazyComponent />
        </React.Suspense>
      )}
    </View>
  );
};

动画优化 #

使用原生动画驱动 #

tsx
import Animated, {useAnimatedStyle, useSharedValue, withSpring} from 'react-native-reanimated';

const OptimizedAnimation = () => {
  const scale = useSharedValue(1);

  const animatedStyle = useAnimatedStyle(() => {
    return {
      transform: [{scale: scale.value}],
    };
  });

  const handlePress = () => {
    scale.value = withSpring(0.9);
  };

  return (
    <Pressable onPress={handlePress}>
      <Animated.View style={[styles.box, animatedStyle]} />
    </Pressable>
  );
};

避免在动画中使用 JS #

tsx
// 不好 - 使用 JS 驱动
Animated.timing(this.state.opacity, {
  toValue: 1,
  duration: 500,
  useNativeDriver: false, // JS 驱动
}).start();

// 好 - 使用原生驱动
Animated.timing(this.state.opacity, {
  toValue: 1,
  duration: 500,
  useNativeDriver: true, // 原生驱动
}).start();

启动优化 #

延迟初始化 #

tsx
const App = () => {
  const [isReady, setIsReady] = useState(false);

  useEffect(() => {
    const init = async () => {
      await Promise.all([
        initAnalytics(),
        initCrashReporting(),
        initPushNotifications(),
      ]);
      setIsReady(true);
    };

    init();
  }, []);

  if (!isReady) {
    return <SplashScreen />;
  }

  return <MainApp />;
};

代码分割 #

tsx
import {lazy, Suspense} from 'react';

const SettingsScreen = lazy(() => import('./SettingsScreen'));
const ProfileScreen = lazy(() => import('./ProfileScreen'));

const App = () => {
  return (
    <Suspense fallback={<Loading />}>
      <SettingsScreen />
    </Suspense>
  );
};

性能监控 #

使用 Performance Monitor #

在开发菜单中启用 “Show Perf Monitor”。

自定义性能监控 #

tsx
const PerformanceMonitor = ({children}) => {
  useEffect(() => {
    const startTime = performance.now();

    return () => {
      const endTime = performance.now();
      console.log(`Component rendered in ${endTime - startTime}ms`);
    };
  });

  return children;
};

使用 React DevTools Profiler #

tsx
import {Profiler} from 'react';

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

  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <MainComponent />
    </Profiler>
  );
};

最佳实践总结 #

渲染优化 #

  • 使用 React.memo 防止不必要渲染
  • 使用 useMemo 缓存计算结果
  • 使用 useCallback 缓存回调函数

列表优化 #

  • 使用 FlatList 而非 ScrollView
  • 设置 getItemLayout 提升性能
  • 合理配置渲染参数

内存优化 #

  • 清理 useEffect 副作用
  • 取消未完成的请求
  • 避免闭包陷阱

动画优化 #

  • 使用原生动画驱动
  • 使用 Reanimated 库
  • 避免在动画中调用 JS

总结 #

性能优化是持续的过程:

  • 渲染优化:减少不必要的渲染
  • 列表优化:正确使用 FlatList
  • 内存优化:及时清理资源
  • 动画优化:使用原生驱动
  • 启动优化:延迟初始化

继续学习 动画系统,了解 React Native 动画实现。

最后更新:2026-03-28