React Native性能优化方案(新旧架构对比,只看这一篇文章即可拿下面试官)

文章开始之前希望大家支持一下我独立开发的微信小程序“头脑旋风”,或微信扫描我的头像进入,谢谢支持~

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

  • 优化渲染和更新逻辑
    • 避免不必要的渲染:
      • 使用 React.memoPureComponent 来避免组件不必要的重新渲染。
      • 合理使用 shouldComponentUpdateReact.useCallback 优化函数组件的性能。
    • FlatList 优化:
      • 使用 keyExtractor 提供唯一键值。
      • 通过设置 initialNumToRendermaxToRenderPerBatchwindowSize 控制渲染的批次和范围。
      • 使用 getItemLayout 提供固定高度以提高滚动性能。
    • 减少匿名函数和内联对象:
      • 避免在 render 方法中直接定义函数和对象,将它们提取为组件外的常量或使用 useMemouseCallback 缓存。
  • 优化 JavaScript 性能
    • 避免复杂计算:
      • 将繁重的计算逻辑放到后台线程,使用库如 react-native-workerWeb Worker
    • 减少 re-renders
      • 利用 ContextRedux 管理全局状态,但避免不必要的深度嵌套,结合 useSelectoruseContext 的浅比较。
  • 图片优化
    • 图片格式:
      • 使用压缩后的图片(如 JPEGWebP),避免加载超高分辨率图片。
    • 缓存:
      • 使用库如 react-native-fast-image 实现图片缓存和加载优化。
    • 按需加载:
      • 通过惰性加载只加载当前屏幕需要的图片。
  • 网络请求优化
    • 压缩和缓存:
      • 启用 GZIP 压缩和 HTTP 缓存。
      • 使用本地数据库(如 RealmSQLite)缓存频繁请求的数据。
  • 减少启动时间
    • 代码拆分:
      • 使用按需加载的方式分拆代码,减少主包体积(如 react-native-screens 的懒加载功能)。
    • 启用 Hermes 引擎:
      • HermesFacebookReact Native 应用设计的 JavaScript 引擎,可减少应用启动时间并优化内存使用。
    • 禁用 Dev Tools
      • 确保在生产环境中关闭 debugyellow box 和其他开发工具。
  • 动画优化
    • 使用原生驱动动画:
      • 使用 Animated 中的 useNativeDriver: true,将动画计算移至原生线程。
    • 选择性能友好的动画库:
      • react-native-reanimatedlottie-react-native,能更高效地处理复杂动画。
  • 内存管理
    • 避免内存泄漏:
      • 在组件卸载时清理定时器、订阅和事件监听器。
      • 在异步操作中添加 isMounted 检查。
    • 管理大列表:
      • 对长列表使用 FlatListSectionList,避免使用 ScrollView 加载所有数据。
  • 监控和调试
    • 使用性能分析工具:
      • React DevTools:分析组件渲染问题。
      • Flipper:用于检查网络请求、日志和性能。
      • Android StudioXcode Profiler:分析原生性能瓶颈。

2.如何减少重新渲染?

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

  • 使用 React.memo
    • React.memo 可以防止函数组件在相同的 props 下重新渲染。
    const MyComponent = React.memo(({ prop1 }) => {
      console.log("Rendering");
      return <Text>{prop1}</Text>;
    });
    
    如果 prop1 未改变,组件不会重新渲染。
  • 避免匿名函数和内联对象
    • 匿名函数或内联对象在每次渲染时都会生成新的引用,可能触发子组件的重新渲染。
    • 问题示例
    const Parent = () => {
      return <Child onClick={() => console.log("Clicked")} />;
    };
    
    • 解决方案
    const handleClick = useCallback(() => {
      console.log("Clicked");
    }, []);
    
    const Parent = () => {
      return <Child onClick={handleClick} />;
    };
    
    useCallback 确保函数引用在依赖不变时保持稳定。
  • 使用 useMemo 缓存计算值
    复杂的计算结果可以通过 useMemo 缓存,避免每次渲染都重新计算。
    const Parent = ({ items }) => {
      const processedItems = useMemo(() => {
        return items.map(item => item * 2);
      }, [items]);
    
      return <Child items={processedItems} />;
    };
    
  • 合理使用 shouldComponentUpdateReact.PureComponent
    对于类组件,可以通过 shouldComponentUpdateReact.PureComponent 控制是否需要重新渲染。
    class MyComponent extends React.PureComponent {
      render() {
        console.log("Rendering");
        return <Text>{this.props.value}</Text>;
      }
    }
    
  • 使用 key 提高列表性能
    在列表渲染中,确保 key 唯一且稳定,避免 React 重新创建 DOM 节点。
     <FlatList
      data={data}
      renderItem={({ item }) => <Item key={item.id} {...item} />}
      keyExtractor={(item) => item.id.toString()}
    />
    
  • 避免不必要的 useEffect 执行
    useEffect 中的逻辑如果没有依赖变化,可以跳过执行。
    • 问题示例
    useEffect(() => {
      console.log("Effect executed");
    });
    
    • 解决方案
    useEffect(() => {
      console.log("Effect executed");
    }, []); // 添加依赖项数组
    
  • 分离状态
    将状态切分到更小的组件或 Context,避免一个状态变化影响整个组件树。
    • 问题示例
    const Parent = () => {
      const [count, setCount] = useState(0);
      return (
        <>
          <ChildA count={count} />
          <ChildB />
        </>
      );
    };
    
    • 解决方案
      使用状态上下文分离:
    const CountContext = React.createContext();
    
    const Parent = () => {
      const [count, setCount] = useState(0);
      return (
        <CountContext.Provider value={count}>
          <ChildA />
          <ChildB />
        </CountContext.Provider>
      );
    };
    
  • 使用状态管理工具
    如果组件需要共享全局状态,可使用 ReduxZustand 等状态管理工具,避免通过 props 层层传递。
  • 避免过大的组件树
    将组件拆分为更小的功能性组件,减小单个组件的渲染范围。
  • 检测和优化性能
    使用工具分析性能瓶颈:
    • React DevTools:检查组件渲染的频率。
    • Profiler API:分析组件渲染时间。
    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 没有变化,就跳过重新渲染。
    • 基本用法
    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
    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 变化。
    • 基本用法
    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 一起使用,确保传递给子组件的回调函数引用不变。
    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 的依赖管理
    确保正确传递依赖项,否则可能导致回调函数的行为异常:
    const Parent = () => {
      const [count, setCount] = useState(0);
    
      // 如果依赖项未设置,当 count 变化时,函数不会更新
      const handleClick = useCallback(() => {
        console.log(count);
      }, [count]); // 添加 count 作为依赖
    
      return <button onClick={handleClick}>Log Count</button>;
    };
    
  • 注意事项
    • 性能权衡:
      • 不要过度使用 React.memouseCallback,它们也有开销,适用于有明显性能问题的场景。
    • 浅比较限制:
      • React.memo 只进行浅比较,传递复杂对象时可能需要自定义比较函数。
    • 依赖列表维护:
      • useCallbackuseMemo 中正确设置依赖,避免错误或不必要的更新。

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

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

  • 为什么需要优化启动时间?
    • 用户体验:
      • 如果应用加载时间过长,用户可能会流失或感到沮丧。数据显示,超过 3 秒的启动时间会显著增加用户放弃应用的概率。
    • 竞争优势:
      • 快速启动的应用更容易吸引用户,尤其在同类应用中,性能是一个显著的优势。
    • 系统资源限制:
      • 启动时间长会占用更多设备资源,影响低端设备或运行多任务时的性能。
    • 提升品牌形象:
      • 快速启动让用户感到应用更专业、可靠,从而提升品牌的整体形象。
  • 如何优化 React Native 的启动时间?
    • 启用 Hermes 引擎
      HermesFacebookReact Native 开发的 JavaScript 引擎,能显著减少应用启动时间,尤其是 Android

      • 操作步骤
        • React Native 项目中启用 Hermes
        npx react-native init MyApp
        
        • 修改 android/app/build.gradle 文件:
        project.ext.react = [
           enableHermes: true  // 启用 Hermes
        ]
        
        • 重新构建应用:
        cd android && ./gradlew clean && cd ..
        npx react-native run-android
        
      • 优势
        • 更快的 JavaScript 初始化时间。
        • 更低的内存使用。
    • 减少 JavaScript 包大小

      • 代码分割:
        • JavaScript 拆分为多个小文件,并按需加载功能。
        • 使用动态 import() 方法按需加载模块。
      • 移除未使用的代码:
        • 使用工具如 babel-plugin-import 按需引入模块。
      • 压缩和混淆代码:
        • 使用 Metro Bundler 自带的压缩功能减少 JavaScript 包大小。
        • 启用生产模式:
        npx react-native run-android --variant=release
        
    • 延迟加载资源

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

      • 移除未使用的原生模块:
        • 确保只链接实际需要的原生模块,减少原生代码加载时间。
        • 使用 react-native-clean-project 清理项目中的多余依赖。
      • 合并原生模块初始化:
        • 如果多个模块需要初始化,尽量将初始化过程合并到一个方法中。5. 减少主线程阻塞
    • 减少主线程阻塞

      • 优化渲染性能:
        • 避免在启动时进行复杂计算,将其推迟到后台线程处理。
        • 使用 InteractionManager.runAfterInteractions 延迟非关键任务:
        InteractionManager.runAfterInteractions(() => {
          // 非关键任务
        });
        
      • 优化启动动画:
        • 在应用启动时提供即时的启动屏幕或动画,减少用户感知的等待时间。
    • 使用原生启动屏幕
      React Native 应用在启动时,可能需要加载 JavaScript 和原生模块。通过添加启动屏幕,可以在后台加载资源时向用户展示品牌形象。

      操作步骤

      • 使用库如 react-native-splash-screen
      • 在启动时加载资源,完成后隐藏启动屏幕。
    • 减少依赖项
      移除不必要的依赖,尤其是会增加启动时间的庞大库。例如:

      • 替换 moment.js(大体积)为 dayjs
      • 避免直接使用未优化的第三方库,如未按需加载的组件库。
    • 监控启动性能
      使用性能监控工具检测启动时间的瓶颈:

    • React Native Performance Monitor:在开发环境中启用性能监控。

    • Flipper:检查网络请求、内存占用、组件加载时间。

    • Android Studio Profiler / Xcode Instruments:分析原生层面的性能问题。

5.什么是 React Nativebridge,它会影响性能吗?

  • 什么是 React NativeBridge
    React Native 中,Bridge 是一个关键概念,用于连接 JavaScript 代码(运行在 JavaScript 引擎中,如 HermesJSC)和原生代码(运行在 AndroidiOS 平台上)。

    • React Native 的核心架构如下:
      • JavaScript 线程:运行 React 和应用逻辑(UI 渲染逻辑、状态管理等)。
      • Bridge:一个通信层,用于在 JavaScript 线程和原生线程之间传递数据。
      • 原生线程:负责原生视图的渲染、动画、手势处理等。
  • Bridge 的作用:

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

    • JavaScript 调用原生模块(通过 Bridge)。
    • 数据打包为 JSON 格式。
    • 通过异步消息队列传递到原生线程。
    • 原生模块处理请求,并将结果通过 Bridge 发送回 JavaScript
  • Bridge 对性能的影响
    由于 React NativeBridge 是异步的消息通道,其性能可能受到以下因素的影响:

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

      1. 减少通信频率
      • 将高频事件的逻辑尽量放在原生代码中处理,减少依赖 JavaScript
      • 优化滚动事件:使用原生实现滚动逻辑(如 FlatListSectionList)。
      1. 减少传输数据量
      • 传递必要的数据,避免大数据对象直接通过 Bridge
      • 对数据进行压缩或拆分处理。
      1. 使用批量处理
      • 如果需要传递多个事件或数据,可以合并成一个消息,通过一次 Bridge 调用完成。
      • 示例:将多次状态更新合并为一个批量更新。
      1. 优化动画
      • 使用 React Native 的原生动画驱动(如 AnimatedLayoutAnimation),而不是依赖 JavaScript 驱动的动画。
      1. 使用 JSIJavaScript Interface
        React Native 的新架构(FabricTurbo Modules)通过 JSI 替代了传统的 BridgeJSI 提供了更高效的同步通信机制,避免了数据序列化和异步队列的开销。
        特点:
      • 支持直接调用原生代码,无需 JSON 序列化。
      • 提升通信效率,尤其适合高频任务。
      • 要启用 JSI,需要确保你的 React Native 版本支持 FabricTurbo Modules
      1. 性能监控
      • 使用工具(如 Flipper)监控 Bridge 的消息队列,分析通信延迟和数据传输量。
      • 找到频繁调用或大数据传输的关键点并优化。
  • 总结

    • Bridge 的优缺点:
      • 优点:异步机制让 JavaScript 和原生线程解耦,降低线程阻塞风险。
      • 缺点:通信延迟、数据序列化等开销可能影响性能,尤其是在高频通信场景下。
    • 优化方向:
      • 避免高频事件依赖 Bridge
      • 使用批量传输减少通信次数。
      • 尽早迁移到支持 JSI 的新架构,进一步提升通信效率。

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

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

    1. 减少通信频率
    • 合并调用
      • 问题:频繁的单次通信会增加 Bridge 的开销。
      • 解决方案:将多次调用合并为一次批量调用。例如,合并状态更新或事件发送。
      	// 示例:批量发送数据
      	const sendData = (dataList) => {
      	  NativeModules.MyNativeModule.sendBatchData(dataList);
      	};
      
    • 本地化高频任务
      • 问题:高频任务(如滚动、动画)如果通过 Bridge 处理,可能导致卡顿。
      • 解决方案:将高频任务逻辑尽量放在原生代码中。
        例如,使用原生实现动画和手势处理:
      • React Native 提供了 AnimatedLayoutAnimation 等可以利用原生线程处理动画的工具。
      • 使用原生组件(如 FlatList)处理滚动,而不是自定义滚动逻辑。
    1. 减少数据传输量
    • 传递必要的数据

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

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

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

      import { gzip } from 'pako';
      
      const compressedData = gzip(JSON.stringify(data));
      NativeModules.MyNativeModule.sendData(compressedData);
      
    1. 减少序列化和反序列化开销
    • 使用轻量级数据结构
      • 避免使用嵌套过深的对象或数组,尽量使用扁平化的结构。
      • 示例:用简单的数组替代复杂的对象树。
    • 迁移到 JSIJavaScript Interface
      • 问题:传统 Bridge 依赖 JSON 序列化和反序列化。
      • 解决方案:在支持新架构(Fabric 和 Turbo Modules)的 React Native 中使用 JSI。
    • 特点:
      • 直接调用原生代码,无需 JSON 序列化。
      • 提高数据传输效率,减少性能损耗。
    1. 优化高频事件处理
    • 减少事件监听器的绑定
      • 问题:过多的事件监听器可能增加通信负担。
      • 解决方案:优化事件监听逻辑,绑定必要的事件。
      // 示例:限制监听范围
      useEffect(() => {
        const subscription = DeviceEventEmitter.addListener('eventName', handleEvent);
        return () => subscription.remove();
      }, []);
      	```
      
    • 延迟非关键任务
      • 将非关键任务延迟到后台线程处理,避免占用主线程时间。
      import { InteractionManager } from 'react-native';
      
      InteractionManager.runAfterInteractions(() => {
        // 执行非关键任务
      });
      
    1. 使用原生模块的能力
    • 原生端缓存
      • 问题:重复传输同样的数据会浪费带宽。
      • 解决方案:将需要频繁访问的数据缓存到原生端,避免重复通信。
    • 事件触发机制
      • 使用原生端的事件触发机制(如 DeviceEventEmitter),通过事件监听代替主动通信。
       //原生模块发送事件
      DeviceEventEmitter.emit('customEvent', { key: 'value' });
      
      // JavaScript 中监听
      DeviceEventEmitter.addListener('customEvent', (data) => {
        console.log(data);
      });
      
    1. 性能监控和调优
    • 监控 Bridge 开销
      • 使用工具如 FlipperReact Native Debugger 监控 Bridge 的通信频率和数据量。
    • 识别瓶颈
      • 找出频繁调用的模块,分析哪些调用是可以合并或优化的。

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

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

    1. 什么是代码分割和动态加载?
    • 代码分割
      将应用程序的代码分为多个小的独立块(chunks),以便按需加载所需的部分,而不是在启动时加载整个代码库。
    • 动态加载
      动态加载允许应用在运行时按需加载某些模块或组件,而不是在初始加载时加载所有代码。
    1. 为什么要实现代码分割和动态加载?
    • 减少初始加载时间:只加载启动时所需的代码,提高应用启动速度。
    • 按需加载:延迟加载不常用的模块,提高运行时性能。
    • 内存优化:避免一次性加载大块代码,减少内存占用。
    1. 在 React Native 中实现代码分割和动态加载
    • 使用 React.lazy 实现组件的动态加载
      示例:懒加载组件

      	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 的支持有限,尤其是某些场景下的服务端渲染。
    • 按需加载模块
      动态加载函数或模块,可以避免一次性加载所有代码。
      示例:动态加载模块

      const loadModule = async () => {
         const module = await import('./SomeModule');
         module.default(); // 使用动态加载的模块
      };
      
      const App = () => (
         <Button title="Load Module" onPress={loadModule} />
      );
      
      export default App;
      
    • 使用 React Navigation 的延迟加载屏幕
      如果使用 React Navigation,可以延迟加载屏幕组件,避免加载所有屏幕的代码。
      示例:延迟加载屏幕

      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;
      
    • 使用 Metro Bundler 的分包功能
      Metro 是 React Native 默认的打包工具,支持代码分包功能。
      实现分包

      • 配置分包:创建一个自定义的 metro.config.js 文件。
      const path = require('path');
      
      module.exports = {
       resolver: {
         // 指定额外的包作为单独的依赖分包
         extraNodeModules: {
           someDependency: path.resolve(__dirname, 'node_modules/some-dependency'),
         },
       },
       transformer: {
         // 启用分包功能
         getTransformOptions: async () => ({
           transform: {
             experimentalImportSupport: true,
             inlineRequires: false,
           },
         }),
       },
      };
      
      • 创建分包入口:将某些模块配置为单独的分包。
    • 使用动态加载的图片和资源
      在 React Native 中,大型图片资源也可以延迟加载。
      示例:动态加载图片

      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>
        );
      };
      
    • 避免加载无关依赖
      通过 Babel 插件(如 babel-plugin-import)按需加载库的模块,减少无关代码的加载。
      示例:按需加载 Ant Design Mobile

      npm install babel-plugin-import --save-dev
      

      配置 .babelrc

      {
        "plugins": [
          ["import", { "libraryName": "antd-mobile", "libraryDirectory": "es", "style": true }]
        ]
      }
      

      然后只加载需要的模块:

      import { Button } from 'antd-mobile'; // 只加载 Button 组件
      
    1. 注意事项
    • 适配性能监控工具
      • 使用工具如 Flipper 监控代码加载情况,确保延迟加载部分按预期执行。
    • 处理动态加载的错误
      • 为动态加载添加错误边界,防止加载失败导致崩溃。
      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>
      );
      
    • 测试用户体验
    • 确保延迟加载的占位符(如 fallback)能提供良好的用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值