1. React Native 中如何优化应用的性能?
优化 React Native 应用性能可以提高用户体验并降低资源消耗。以下是一些关键优化技巧:
1. 优化渲染和更新逻辑
-
避免不必要的渲染:
- 使用
React.memo
或PureComponent
来避免组件不必要的重新渲染。 - 合理使用
shouldComponentUpdate
或React.useCallback
优化函数组件的性能。
- 使用
-
FlatList 优化:
- 使用
keyExtractor
提供唯一键值。 - 通过设置
initialNumToRender
、maxToRenderPerBatch
和windowSize
控制渲染的批次和范围。 - 使用
getItemLayout
提供固定高度以提高滚动性能。
- 使用
-
减少匿名函数和内联对象:
- 避免在
render
方法中直接定义函数和对象,将它们提取为组件外的常量或使用useMemo
、useCallback
缓存。
- 避免在
2. 优化 JavaScript 性能
-
避免复杂计算:
- 将繁重的计算逻辑放到后台线程,使用库如 react-native-worker 或 Web Worker。
-
减少 re-renders:
- 利用
Context
或 Redux 管理全局状态,但避免不必要的深度嵌套,结合useSelector
或useContext
的浅比较。
- 利用
3. 图片优化
-
图片格式:
- 使用压缩后的图片(如
JPEG
、WebP
),避免加载超高分辨率图片。
- 使用压缩后的图片(如
-
缓存:
- 使用库如 react-native-fast-image 实现图片缓存和加载优化。
-
按需加载:
- 通过惰性加载只加载当前屏幕需要的图片。
4. 网络请求优化
-
压缩和缓存:
- 启用 GZIP 压缩和 HTTP 缓存。
- 使用本地数据库(如 Realm 或 SQLite)缓存频繁请求的数据。
-
批量请求:
- 合并多个请求以减少网络开销。
-
节流和去抖:
- 对高频操作(如搜索)使用节流(throttle)或去抖(debounce)优化。
5. 减少启动时间
-
代码拆分:
- 使用按需加载的方式分拆代码,减少主包体积(如
react-native-screens
的懒加载功能)。
- 使用按需加载的方式分拆代码,减少主包体积(如
-
启用 Hermes 引擎:
- Hermes 是 Facebook 为 React Native 应用设计的 JavaScript 引擎,可减少应用启动时间并优化内存使用。
-
禁用 Dev Tools:
- 确保在生产环境中关闭
debug
、yellow box
和其他开发工具。
- 确保在生产环境中关闭
6. 动画优化
- 使用原生驱动动画 :
- 使用
Animated
中的useNativeDriver: true
,将动画计算移至原生线程。
- 使用
- 选择性能友好的动画库 :
- 如
react-native-reanimated
或lottie-react-native
,能更高效地处理复杂动画。
- 如
7. 内存管理
-
避免内存泄漏:
- 在组件卸载时清理定时器、订阅和事件监听器。
- 在异步操作中添加
isMounted
检查。
-
管理大列表:
- 对长列表使用
FlatList
或SectionList
,避免使用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. 合理使用 shouldComponentUpdate
或 React.PureComponent
对于类组件,可以通过 shouldComponentUpdate
或 React.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.memo
和 useCallback
是优化组件性能的常用工具。它们可以帮助减少不必要的重新渲染,从而提高应用的效率。
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
重新渲染时,由于useCallback
,Child
组件不会重新渲染,因为onClick
函数引用没有变化。
与 useCallback
和 React.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>;
};
注意事项
-
性能权衡:
- 不要过度使用
React.memo
和useCallback
,它们也有开销,适用于有明显性能问题的场景。
- 不要过度使用
-
浅比较限制:
React.memo
只进行浅比较,传递复杂对象时可能需要自定义比较函数。
-
依赖列表维护:
- 在
useCallback
和useMemo
中正确设置依赖,避免错误或不必要的更新。
- 在
4. 为什么需要优化 React Native 的启动时间?如何进行优化?
优化 React Native 应用的启动时间是提升用户体验的关键因素,尤其在移动设备上,用户对应用响应速度非常敏感。以下是优化启动时间的原因及具体方法。
为什么需要优化启动时间?
-
用户体验:
- 如果应用加载时间过长,用户可能会流失或感到沮丧。数据显示,超过 3 秒的启动时间会显著增加用户放弃应用的概率。
-
竞争优势:
- 快速启动的应用更容易吸引用户,尤其在同类应用中,性能是一个显著的优势。
-
系统资源限制:
- 启动时间长会占用更多设备资源,影响低端设备或运行多任务时的性能。
-
提升品牌形象:
- 快速启动让用户感到应用更专业、可靠,从而提升品牌的整体形象。
如何优化 React Native 的启动时间?
1. 启用 Hermes 引擎
Hermes 是 Facebook 为 React Native 开发的 JavaScript 引擎,能显著减少应用启动时间,尤其是 Android。
操作步骤
- 在 React Native 项目中启用 Hermes:
bash
npx react-native init MyApp
修改 android/app/build.gradle
文件:
gradle
project.ext.react = [
enableHermes: true // 启用 Hermes
]
- 重新构建应用:
bash
cd android && ./gradlew clean && cd ..
npx react-native run-android
优势
- 更快的 JavaScript 初始化时间。
- 更低的内存使用。
2. 减少 JavaScript 包大小
-
代码分割:
- 将 JavaScript 拆分为多个小文件,并按需加载功能。
- 使用动态
import()
方法按需加载模块。
-
移除未使用的代码:
- 使用工具如 babel-plugin-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
延迟非关键任务:jsxInteractionManager.runAfterInteractions(() => { // 非关键任务 });
-
-
优化启动动画:
- 在应用启动时提供即时的启动屏幕或动画,减少用户感知的等待时间。
6. 使用原生启动屏幕
React Native 应用在启动时,可能需要加载 JavaScript 和原生模块。通过添加启动屏幕,可以在后台加载资源时向用户展示品牌形象。
操作步骤
- 使用库如 react-native-splash-screen。
- 在启动时加载资源,完成后隐藏启动屏幕。
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 的核心架构如下:
- JavaScript 线程:运行 React 和应用逻辑(UI 渲染逻辑、状态管理等)。
- Bridge:一个通信层,用于在 JavaScript 线程和原生线程之间传递数据。
- 原生线程:负责原生视图的渲染、动画、手势处理等。
Bridge 的作用:
- 它通过异步消息传递,让 JavaScript 代码调用原生模块(如摄像头、地理定位)。
- 同样,原生模块也可以通过 Bridge 把数据传回 JavaScript。
通信过程:
- JavaScript 调用原生模块(通过 Bridge)。
- 数据打包为 JSON 格式。
- 通过异步消息队列传递到原生线程。
- 原生模块处理请求,并将结果通过 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 的原生动画驱动(如
Animated
和LayoutAnimation
),而不是依赖 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 提供了
Animated
和LayoutAnimation
等可以利用原生线程处理动画的工具。 - 使用原生组件(如
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 开销
- 使用工具如 Flipper 和 React 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;
(3)使用 React Navigation 的延迟加载屏幕
如果使用 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 默认的打包工具,支持代码分包功能。
实现分包
- 配置分包 : 创建一个自定义的
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,
},
}),
},
};
- 创建分包入口: 将某些模块配置为单独的分包。
(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. 注意事项
-
适配性能监控工具
- 使用工具如 Flipper 监控代码加载情况,确保延迟加载部分按预期执行。
-
处理动态加载的错误
- 为动态加载添加错误边界,防止加载失败导致崩溃。
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>
);
- 测试用户体验
- 确保延迟加载的占位符(如
fallback
)能提供良好的用户体验。
- 确保延迟加载的占位符(如