React Native性能优化

1. React Native 中如何优化应用的性能?

优化 React Native 应用性能可以提高用户体验并降低资源消耗。以下是一些关键优化技巧:


1. 优化渲染和更新逻辑

  • 避免不必要的渲染

    • 使用 React.memoPureComponent 来避免组件不必要的重新渲染。
    • 合理使用 shouldComponentUpdateReact.useCallback 优化函数组件的性能。
  • FlatList 优化

    • 使用 keyExtractor 提供唯一键值。
    • 通过设置 initialNumToRendermaxToRenderPerBatchwindowSize 控制渲染的批次和范围。
    • 使用 getItemLayout 提供固定高度以提高滚动性能。
  • 减少匿名函数和内联对象

    • 避免在 render 方法中直接定义函数和对象,将它们提取为组件外的常量或使用 useMemouseCallback 缓存。

2. 优化 JavaScript 性能

  • 避免复杂计算

    • 将繁重的计算逻辑放到后台线程,使用库如 react-native-worker 或 Web Worker。
  • 减少 re-renders

    • 利用 Context 或 Redux 管理全局状态,但避免不必要的深度嵌套,结合 useSelectoruseContext 的浅比较。

3. 图片优化

  • 图片格式

    • 使用压缩后的图片(如 JPEGWebP),避免加载超高分辨率图片。
  • 缓存

  • 按需加载

    • 通过惰性加载只加载当前屏幕需要的图片。

4. 网络请求优化

  • 压缩和缓存

    • 启用 GZIP 压缩和 HTTP 缓存。
    • 使用本地数据库(如 Realm 或 SQLite)缓存频繁请求的数据。
  • 批量请求

    • 合并多个请求以减少网络开销。
  • 节流和去抖

    • 对高频操作(如搜索)使用节流(throttle)或去抖(debounce)优化。

5. 减少启动时间

  • 代码拆分

    • 使用按需加载的方式分拆代码,减少主包体积(如 react-native-screens 的懒加载功能)。
  • 启用 Hermes 引擎

    • Hermes 是 Facebook 为 React Native 应用设计的 JavaScript 引擎,可减少应用启动时间并优化内存使用。
  • 禁用 Dev Tools

    • 确保在生产环境中关闭 debugyellow box 和其他开发工具。

6. 动画优化

  • 使用原生驱动动画
    • 使用 Animated 中的 useNativeDriver: true,将动画计算移至原生线程。
  • 选择性能友好的动画库
    • react-native-reanimatedlottie-react-native,能更高效地处理复杂动画。

7. 内存管理

  • 避免内存泄漏

    • 在组件卸载时清理定时器、订阅和事件监听器。
    • 在异步操作中添加 isMounted 检查。
  • 管理大列表

    • 对长列表使用 FlatListSectionList,避免使用 ScrollView 加载所有数据。

8. 监控和调试

  • 使用性能分析工具:
    • React DevTools:分析组件渲染问题。
    • Flipper:用于检查网络请求、日志和性能。
    • Android Studio 和 Xcode Profiler:分析原生性能瓶颈。

2. 如何减少重新渲染?

在 React 或 React Native 中,减少组件的重新渲染是优化性能的关键。以下是一些减少不必要重新渲染的方法:


1. 使用 React.memo

React.memo 可以防止函数组件在相同的 props 下重新渲染。

jsx 复制代码
const MyComponent = React.memo(({ prop1 }) => {
  console.log("Rendering");
  return <Text>{prop1}</Text>;
});

如果 prop1 未改变,组件不会重新渲染。


2. 避免匿名函数和内联对象

匿名函数或内联对象在每次渲染时都会生成新的引用,可能触发子组件的重新渲染。

问题示例

jsx 复制代码
const Parent = () => {
  return <Child onClick={() => console.log("Clicked")} />;
};

解决方案

jsx 复制代码
const handleClick = useCallback(() => {
  console.log("Clicked");
}, []);

const Parent = () => {
  return <Child onClick={handleClick} />;
};

useCallback 确保函数引用在依赖不变时保持稳定。


3. 使用 useMemo 缓存计算值

复杂的计算结果可以通过 useMemo 缓存,避免每次渲染都重新计算。

jsx 复制代码
const Parent = ({ items }) => {
  const processedItems = useMemo(() => {
    return items.map(item => item * 2);
  }, [items]);

  return <Child items={processedItems} />;
};

4. 合理使用 shouldComponentUpdateReact.PureComponent

对于类组件,可以通过 shouldComponentUpdateReact.PureComponent 控制是否需要重新渲染。

jsx 复制代码
class MyComponent extends React.PureComponent {
  render() {
    console.log("Rendering");
    return <Text>{this.props.value}</Text>;
  }
}

5. 使用 key 提高列表性能

在列表渲染中,确保 key 唯一且稳定,避免 React 重新创建 DOM 节点。

jsx 复制代码
<FlatList
  data={data}
  renderItem={({ item }) => <Item key={item.id} {...item} />}
  keyExtractor={(item) => item.id.toString()}
/>

6. 避免不必要的 useEffect 执行

useEffect 中的逻辑如果没有依赖变化,可以跳过执行。

问题示例

jsx 复制代码
useEffect(() => {
  console.log("Effect executed");
});

解决方案

jsx 复制代码
useEffect(() => {
  console.log("Effect executed");
}, []); // 添加依赖项数组

7. 分离状态

将状态切分到更小的组件或 Context,避免一个状态变化影响整个组件树。

问题示例

jsx 复制代码
const Parent = () => {
  const [count, setCount] = useState(0);
  return (
    <>
      <ChildA count={count} />
      <ChildB />
    </>
  );
};

解决方案

使用状态上下文分离:

jsx 复制代码
const CountContext = React.createContext();

const Parent = () => {
  const [count, setCount] = useState(0);
  return (
    <CountContext.Provider value={count}>
      <ChildA />
      <ChildB />
    </CountContext.Provider>
  );
};

8. 使用状态管理工具

如果组件需要共享全局状态,可使用 Redux 或 Zustand 等状态管理工具,避免通过 props 层层传递。


9. 避免过大的组件树

将组件拆分为更小的功能性组件,减小单个组件的渲染范围。


10. 检测和优化性能

使用工具分析性能瓶颈:

  • React DevTools:检查组件渲染的频率。
  • Profiler API:分析组件渲染时间。
jsx 复制代码
import { Profiler } from "react";

const Parent = () => (
  <Profiler id="Parent" onRender={(id, phase, actualTime) => {
    console.log({ id, phase, actualTime });
  }}>
    <Child />
  </Profiler>
);

3. 如何使用 memo 和 useCallback?

在 React 中,React.memouseCallback 是优化组件性能的常用工具。它们可以帮助减少不必要的重新渲染,从而提高应用的效率。


React.memo 的用法

React.memo 是一个高阶组件,用于优化函数组件。它会对组件的 props 进行浅比较,如果 props 没有变化,就跳过重新渲染。

基本用法

jsx 复制代码
import React from "react";

const MyComponent = React.memo(({ value }) => {
  console.log("Rendered!");
  return <div>{value}</div>;
});

const Parent = () => {
  const [count, setCount] = React.useState(0);
  return (
    <>
      <MyComponent value="Hello" />
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </>
  );
};
输出

即使 Parent 组件重新渲染,MyComponent 也不会重新渲染,因为它的 props 没有变化。


与自定义比较函数结合

React.memo 默认使用浅比较,但你可以通过传递自定义比较函数来处理复杂 props

jsx 复制代码
const MyComponent = React.memo(
  ({ value }) => {
    console.log("Rendered!");
    return <div>{value.text}</div>;
  },
  (prevProps, nextProps) => {
    // 自定义比较:如果 `value.text` 没变,不重新渲染
    return prevProps.value.text === nextProps.value.text;
  }
);

useCallback 的用法

useCallback 是一个 React Hook,用于缓存函数的引用。它会在依赖未改变时返回相同的函数实例。

为什么需要 useCallback

在 React 中,每次渲染都会重新创建函数实例。通过 useCallback 可以避免不必要的函数重新创建,从而减少传递给子组件的 props 变化。

基本用法

jsx 复制代码
import React, { useState, useCallback } from "react";

const Child = React.memo(({ onClick }) => {
  console.log("Child Rendered!");
  return <button onClick={onClick}>Click Me</button>;
});

const Parent = () => {
  const [count, setCount] = useState(0);

  // 如果不使用 useCallback,每次渲染都会生成新的函数实例
  const handleClick = useCallback(() => {
    console.log("Button clicked");
  }, []); // 依赖为空,函数实例只会创建一次

  return (
    <>
      <p>Count: {count}</p>
      <Child onClick={handleClick} />
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </>
  );
};
输出
  • 每次 Parent 重新渲染时,由于 useCallbackChild 组件不会重新渲染,因为 onClick 函数引用没有变化。

useCallbackReact.memo 配合

useCallback 常与 React.memo 一起使用,确保传递给子组件的回调函数引用不变。

jsx 复制代码
const Child = React.memo(({ onClick }) => {
  console.log("Child Rendered!");
  return <button onClick={onClick}>Click Me</button>;
});

const Parent = () => {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log("Button clicked");
  }, []);

  return (
    <>
      <Child onClick={handleClick} />
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </>
  );
};

useCallback 的依赖管理

确保正确传递依赖项,否则可能导致回调函数的行为异常:

jsx 复制代码
const Parent = () => {
  const [count, setCount] = useState(0);

  // 如果依赖项未设置,当 count 变化时,函数不会更新
  const handleClick = useCallback(() => {
    console.log(count);
  }, [count]); // 添加 count 作为依赖

  return <button onClick={handleClick}>Log Count</button>;
};

注意事项

  1. 性能权衡

    • 不要过度使用 React.memouseCallback,它们也有开销,适用于有明显性能问题的场景。
  2. 浅比较限制

    • React.memo 只进行浅比较,传递复杂对象时可能需要自定义比较函数。
  3. 依赖列表维护

    • useCallbackuseMemo 中正确设置依赖,避免错误或不必要的更新。

4. 为什么需要优化 React Native 的启动时间?如何进行优化?

优化 React Native 应用的启动时间是提升用户体验的关键因素,尤其在移动设备上,用户对应用响应速度非常敏感。以下是优化启动时间的原因及具体方法。


为什么需要优化启动时间?

  1. 用户体验

    • 如果应用加载时间过长,用户可能会流失或感到沮丧。数据显示,超过 3 秒的启动时间会显著增加用户放弃应用的概率。
  2. 竞争优势

    • 快速启动的应用更容易吸引用户,尤其在同类应用中,性能是一个显著的优势。
  3. 系统资源限制

    • 启动时间长会占用更多设备资源,影响低端设备或运行多任务时的性能。
  4. 提升品牌形象

    • 快速启动让用户感到应用更专业、可靠,从而提升品牌的整体形象。

如何优化 React Native 的启动时间?

1. 启用 Hermes 引擎

Hermes 是 Facebook 为 React Native 开发的 JavaScript 引擎,能显著减少应用启动时间,尤其是 Android。

操作步骤
  1. 在 React Native 项目中启用 Hermes:
bash 复制代码
npx react-native init MyApp

修改 android/app/build.gradle 文件:

gradle 复制代码
project.ext.react = [
   enableHermes: true  // 启用 Hermes
]
  1. 重新构建应用:
bash 复制代码
cd android && ./gradlew clean && cd ..
npx react-native run-android
优势
  • 更快的 JavaScript 初始化时间。
  • 更低的内存使用。

2. 减少 JavaScript 包大小

  • 代码分割

    • 将 JavaScript 拆分为多个小文件,并按需加载功能。
    • 使用动态 import() 方法按需加载模块。
  • 移除未使用的代码

  • 压缩和混淆代码

    • 使用 Metro Bundler 自带的压缩功能减少 JavaScript 包大小。
    • 启用生产模式:
bash 复制代码
npx react-native run-android --variant=release

3. 延迟加载资源

  • 懒加载组件
    • 对不需要立即显示的组件和功能进行懒加载。
jsx 复制代码
const LazyComponent = React.lazy(() => import('./LazyComponent'));
const App = () => (
  <React.Suspense fallback={<Text>Loading...</Text>}>
    <LazyComponent />
  </React.Suspense>
);
  • 按需加载图片
    • 使用低分辨率占位符,加载后再替换为高分辨率图片。

4. 优化原生模块加载

  • 移除未使用的原生模块

    • 确保只链接实际需要的原生模块,减少原生代码加载时间。
    • 使用 react-native-clean-project 清理项目中的多余依赖。
  • 合并原生模块初始化

    • 如果多个模块需要初始化,尽量将初始化过程合并到一个方法中。

5. 减少主线程阻塞

  • 优化渲染性能

    • 避免在启动时进行复杂计算,将其推迟到后台线程处理。

    • 使用 InteractionManager.runAfterInteractions 延迟非关键任务:

      jsx 复制代码
      InteractionManager.runAfterInteractions(() => {
        // 非关键任务
      });
  • 优化启动动画

    • 在应用启动时提供即时的启动屏幕或动画,减少用户感知的等待时间。

6. 使用原生启动屏幕

React Native 应用在启动时,可能需要加载 JavaScript 和原生模块。通过添加启动屏幕,可以在后台加载资源时向用户展示品牌形象。

操作步骤
  1. 使用库如 react-native-splash-screen
  2. 在启动时加载资源,完成后隐藏启动屏幕。

7. 减少依赖项

移除不必要的依赖,尤其是会增加启动时间的庞大库。例如:

  • 替换 moment.js(大体积)为 dayjs
  • 避免直接使用未优化的第三方库,如未按需加载的组件库。

8. 监控启动性能

使用性能监控工具检测启动时间的瓶颈:

  • React Native Performance Monitor:在开发环境中启用性能监控。
  • Flipper:检查网络请求、内存占用、组件加载时间。
  • Android Studio Profiler / Xcode Instruments:分析原生层面的性能问题。

5. 什么是 React Native 的 bridge,它会影响性能吗?

什么是 React Native 的 Bridge?

在 React Native 中,Bridge 是一个关键概念,用于连接 JavaScript 代码(运行在 JavaScript 引擎中,如 Hermes 或 JSC)和原生代码(运行在 Android 和 iOS 平台上)。

React Native 的核心架构如下:

  1. JavaScript 线程:运行 React 和应用逻辑(UI 渲染逻辑、状态管理等)。
  2. Bridge:一个通信层,用于在 JavaScript 线程和原生线程之间传递数据。
  3. 原生线程:负责原生视图的渲染、动画、手势处理等。

Bridge 的作用

  • 它通过异步消息传递,让 JavaScript 代码调用原生模块(如摄像头、地理定位)。
  • 同样,原生模块也可以通过 Bridge 把数据传回 JavaScript。

通信过程

  1. JavaScript 调用原生模块(通过 Bridge)。
  2. 数据打包为 JSON 格式。
  3. 通过异步消息队列传递到原生线程。
  4. 原生模块处理请求,并将结果通过 Bridge 发送回 JavaScript。

Bridge 对性能的影响

由于 React Native 的 Bridge 是异步的消息通道,其性能可能受到以下因素的影响:

1. 通信延迟
  • 每次跨越 JavaScript 和原生层的通信,都会有一定的延迟。
  • 如果通信频率高(例如频繁更新 UI、滚动动画),Bridge 的性能瓶颈会导致卡顿。
2. 数据序列化开销
  • 传递数据时需要将 JavaScript 对象序列化为 JSON 格式,原生端需要将其反序列化。
  • 如果传递的数据量很大(如大图片、复杂数据结构),序列化和反序列化的开销会明显增加。
3. 高频调用问题
  • 高频事件(如动画帧、手势处理)如果依赖 Bridge,可能因为消息队列拥堵而导致掉帧。
  • 示例:如果滚动事件需要通过 JavaScript 处理,Bridge 可能成为性能瓶颈。
4. 多线程并发问题
  • React Native 中,JavaScript 和原生线程独立运行。虽然这是为了避免阻塞,但如果线程之间的消息同步不及时,可能出现性能问题。

如何优化 Bridge 性能?

1. 减少通信频率
  • 将高频事件的逻辑尽量放在原生代码中处理,减少依赖 JavaScript。
  • 优化滚动事件:使用原生实现滚动逻辑(如 FlatList 或 SectionList)。
2. 减少传输数据量
  • 传递必要的数据,避免大数据对象直接通过 Bridge。
  • 对数据进行压缩或拆分处理。
3. 使用批量处理
  • 如果需要传递多个事件或数据,可以合并成一个消息,通过一次 Bridge 调用完成。
  • 示例:将多次状态更新合并为一个批量更新。
4. 优化动画
  • 使用 React Native 的原生动画驱动(如 AnimatedLayoutAnimation),而不是依赖 JavaScript 驱动的动画。
5. 使用 JSI(JavaScript Interface)

React Native 的新架构(Fabric 和 Turbo Modules)通过 JSI 替代了传统的 Bridge。JSI 提供了更高效的同步通信机制,避免了数据序列化和异步队列的开销。

特点

  • 支持直接调用原生代码,无需 JSON 序列化。
  • 提升通信效率,尤其适合高频任务。

要启用 JSI,需要确保你的 React Native 版本支持 Fabric 和 Turbo Modules。

6. 性能监控
  • 使用工具(如 Flipper)监控 Bridge 的消息队列,分析通信延迟和数据传输量。
  • 找到频繁调用或大数据传输的关键点并优化。

总结

Bridge 的优缺点

  • 优点:异步机制让 JavaScript 和原生线程解耦,降低线程阻塞风险。
  • 缺点:通信延迟、数据序列化等开销可能影响性能,尤其是在高频通信场景下。

优化方向

  • 避免高频事件依赖 Bridge。
  • 使用批量传输减少通信次数。
  • 尽早迁移到支持 JSI 的新架构,进一步提升通信效率。

6. 如何减少 JavaScript 和原生模块之间的通信开销?

减少 JavaScript 和原生模块之间的通信开销是优化 React Native 应用性能的关键。以下是一些有效的策略和实践方法:


1. 减少通信频率

合并调用

  • 问题:频繁的单次通信会增加 Bridge 的开销。
  • 解决方案:将多次调用合并为一次批量调用。例如,合并状态更新或事件发送。
javascript 复制代码
// 示例:批量发送数据
const sendData = (dataList) => {
  NativeModules.MyNativeModule.sendBatchData(dataList);
};

本地化高频任务

  • 问题:高频任务(如滚动、动画)如果通过 Bridge 处理,可能导致卡顿。
  • 解决方案:将高频任务逻辑尽量放在原生代码中。

例如,使用原生实现动画和手势处理:

  • React Native 提供了 AnimatedLayoutAnimation 等可以利用原生线程处理动画的工具。
  • 使用原生组件(如 FlatList)处理滚动,而不是自定义滚动逻辑。

2. 减少数据传输量

传递必要的数据

  • 问题:传递大数据对象或冗余数据会增加序列化和反序列化的时间。
  • 解决方案:只传递关键数据,避免整个对象通过 Bridge。
javascript 复制代码
// 示例:仅传递必要字段
const sendUserData = (user) => {
  NativeModules.MyNativeModule.sendUserData({
    id: user.id,
    name: user.name,
  });
};

数据压缩

  • 问题:数据量过大可能导致性能瓶颈。
  • 解决方案:在 JavaScript 层对数据进行压缩,再通过 Bridge 传递。

例如,将 JSON 数据压缩成字符串:

javascript 复制代码
import { gzip } from 'pako';

const compressedData = gzip(JSON.stringify(data));
NativeModules.MyNativeModule.sendData(compressedData);

3. 减少序列化和反序列化开销

使用轻量级数据结构

  • 避免使用嵌套过深的对象或数组,尽量使用扁平化的结构。
  • 示例:用简单的数组替代复杂的对象树。

迁移到 JSI(JavaScript Interface)

  • 问题:传统 Bridge 依赖 JSON 序列化和反序列化。
  • 解决方案:在支持新架构(Fabric 和 Turbo Modules)的 React Native 中使用 JSI。

特点

  • 直接调用原生代码,无需 JSON 序列化。
  • 提高数据传输效率,减少性能损耗。

4. 优化高频事件处理

减少事件监听器的绑定

  • 问题:过多的事件监听器可能增加通信负担。
  • 解决方案:优化事件监听逻辑,绑定必要的事件。
javascript 复制代码
// 示例:限制监听范围
useEffect(() => {
  const subscription = DeviceEventEmitter.addListener('eventName', handleEvent);
  return () => subscription.remove();
}, []);

延迟非关键任务

  • 将非关键任务延迟到后台线程处理,避免占用主线程时间。
javascript 复制代码
import { InteractionManager } from 'react-native';

InteractionManager.runAfterInteractions(() => {
  // 执行非关键任务
});

5. 使用原生模块的能力

原生端缓存

  • 问题:重复传输同样的数据会浪费带宽。
  • 解决方案:将需要频繁访问的数据缓存到原生端,避免重复通信。

事件触发机制

  • 使用原生端的事件触发机制(如 DeviceEventEmitter),通过事件监听代替主动通信。
javascript 复制代码
// 原生模块发送事件
DeviceEventEmitter.emit('customEvent', { key: 'value' });

// JavaScript 中监听
DeviceEventEmitter.addListener('customEvent', (data) => {
  console.log(data);
});

6. 性能监控和调优

监控 Bridge 开销

  • 使用工具如 FlipperReact Native Debugger 监控 Bridge 的通信频率和数据量。

识别瓶颈

  • 找出频繁调用的模块,分析哪些调用是可以合并或优化的。

7. 如何实现代码分割和动态加载?

在 React Native 中,代码分割和动态加载是优化性能、减少初始加载时间的关键技术。以下是实现代码分割和动态加载的详细指南:


1. 什么是代码分割和动态加载?

代码分割

将应用程序的代码分为多个小的独立块(chunks),以便按需加载所需的部分,而不是在启动时加载整个代码库。

动态加载

动态加载允许应用在运行时按需加载某些模块或组件,而不是在初始加载时加载所有代码。


2. 为什么要实现代码分割和动态加载?

  • 减少初始加载时间: 只加载启动时所需的代码,提高应用启动速度。

  • 按需加载: 延迟加载不常用的模块,提高运行时性能。

  • 内存优化: 避免一次性加载大块代码,减少内存占用。


3. 在 React Native 中实现代码分割和动态加载

(1)使用 React.lazy 实现组件的动态加载

React.lazy 是 React 内置的工具,可以用来按需加载组件。

示例:懒加载组件
javascript 复制代码
import React, { Suspense } from 'react';

// 动态加载组件
const LazyComponent = React.lazy(() => import('./LazyComponent'));

const App = () => (
  <Suspense fallback={<Text>Loading...</Text>}>
    <LazyComponent />
  </Suspense>
);

export default App;

注意

  • React.lazy 需要配合 Suspense 使用,fallback 属性用于在组件加载时显示占位内容。
  • 在 React Native 中,Suspense 的支持有限,尤其是某些场景下的服务端渲染。

(2)按需加载模块

动态加载函数或模块,可以避免一次性加载所有代码。

示例:动态加载模块
javascript 复制代码
const loadModule = async () => {
  const module = await import('./SomeModule');
  module.default(); // 使用动态加载的模块
};

const App = () => (
  <Button title="Load Module" onPress={loadModule} />
);

export default App;

如果使用 React Navigation,可以延迟加载屏幕组件,避免加载所有屏幕的代码。

示例:延迟加载屏幕
javascript 复制代码
import React, { Suspense } from 'react';
import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

const LazyScreen = React.lazy(() => import('./LazyScreen'));

const App = () => (
  <Stack.Navigator>
    <Stack.Screen
      name="LazyScreen"
      component={() => (
        <Suspense fallback={<Text>Loading Screen...</Text>}>
          <LazyScreen />
        </Suspense>
      )}
    />
  </Stack.Navigator>
);

export default App;

(4)使用 Metro Bundler 的分包功能

Metro 是 React Native 默认的打包工具,支持代码分包功能。

实现分包
  1. 配置分包 : 创建一个自定义的 metro.config.js 文件。
javascript 复制代码
const path = require('path');

module.exports = {
 resolver: {
   // 指定额外的包作为单独的依赖分包
   extraNodeModules: {
     someDependency: path.resolve(__dirname, 'node_modules/some-dependency'),
   },
 },
 transformer: {
   // 启用分包功能
   getTransformOptions: async () => ({
     transform: {
       experimentalImportSupport: true,
       inlineRequires: false,
     },
   }),
 },
};
  1. 创建分包入口: 将某些模块配置为单独的分包。

(5)使用动态加载的图片和资源

在 React Native 中,大型图片资源也可以延迟加载。

示例:动态加载图片
javascript 复制代码
const LazyImage = ({ uri }) => {
  const [loaded, setLoaded] = React.useState(false);

  return (
    <View>
      {!loaded && <ActivityIndicator />}
      <Image
        source={{ uri }}
        onLoad={() => setLoaded(true)}
        style={{ width: 100, height: 100 }}
      />
    </View>
  );
};

(6)避免加载无关依赖

通过 Babel 插件(如 babel-plugin-import)按需加载库的模块,减少无关代码的加载。

示例:按需加载 Ant Design Mobile
bash 复制代码
npm install babel-plugin-import --save-dev

配置 .babelrc

json 复制代码
{
  "plugins": [
    ["import", { "libraryName": "antd-mobile", "libraryDirectory": "es", "style": true }]
  ]
}

然后只加载需要的模块:

javascript 复制代码
import { Button } from 'antd-mobile'; // 只加载 Button 组件

4. 注意事项

  1. 适配性能监控工具

    • 使用工具如 Flipper 监控代码加载情况,确保延迟加载部分按预期执行。
  2. 处理动态加载的错误

    • 为动态加载添加错误边界,防止加载失败导致崩溃。
javascript 复制代码
class ErrorBoundary extends React.Component {
 state = { hasError: false };

 static getDerivedStateFromError(error) {
   return { hasError: true };
 }

 render() {
   if (this.state.hasError) {
     return <Text>Something went wrong!</Text>;
   }
   return this.props.children;
 }
}

const App = () => (
 <ErrorBoundary>
   <Suspense fallback={<Text>Loading...</Text>}>
     <LazyComponent />
   </Suspense>
 </ErrorBoundary>
);
  1. 测试用户体验
    • 确保延迟加载的占位符(如 fallback)能提供良好的用户体验。
相关推荐
爱上语文4 分钟前
Ajax入门程序
前端·javascript·css·ajax·html
北国1379 分钟前
python端拉流检测后再推流到流媒体服务器实现前端拉流查看(多摄像头切换)
服务器·前端·python·opencv·流媒体服务器
木子七11 分钟前
vue3-组件通信
前端·vue
乐闻x14 分钟前
Vue 是如何实现数据双向绑定的?
前端·vue.js
乐闻x15 分钟前
Vue 3 实现高性能拖拽指令的最佳实践
前端·javascript·vue.js
陈逸轩*^_^*27 分钟前
硅谷甄选前端项目环境配置笔记
前端·笔记
橙子家28 分钟前
Element-UI 中关于 Table 的几个功能点简介(行列的合并和样式、合计行配置等)
前端
瓶子丶32 分钟前
Vue实现一个“蛇形”步骤条
前端
且听风吟72038 分钟前
JS综合解决方案5——模块化和构建工具
javascript·面试
海绵波波1071 小时前
集群聊天服务器面试问题
运维·服务器·面试