【RN鸿蒙教学|第10课时】应用异常处理+性能优化实战:夯实稳定性,备战打包部署
【RN鸿蒙教学第10课时摘要】本课程聚焦React Native鸿蒙应用的异常处理与性能优化实战。内容涵盖:1)环境准备(确认工程、设备连接及工具状态);2)异常处理方案(ErrorBoundary组件封装、全局异常捕获、Axios网络请求拦截);3)性能优化技巧(列表渲染控制、组件懒加载)。特别针对鸿蒙开发板性能特点,提供了字体适配、超时延长等优化建议。通过完整代码示例(含错误修复)演示如何构建
·
🚀【RN鸿蒙教学|第10课时】应用异常处理+性能优化实战:夯实稳定性,备战打包部署
📋 一、课前准备(5分钟)
🛠️ 1.1 环境与工程确认
- ✅ 确认
rnHarmonyDemo工程可正常运行,RN版本0.72.7,依赖无冲突; - ✅ 鸿蒙真机开启开发者模式,开发板(DAYU200)连接正常;
- ✅ 工具:DevEco Studio、VSCode、Git Bash 均正常启动。
🔀 1.2 分支管理(新手友好命令)
# 切换到主分支并拉取最新代码
git checkout main
git pull
# 新建feature分支(规范命名)
git checkout -b feature-exception-handle-performance-optimize
📚 1.3 预习核心API速查
| 功能 | 核心API/方法 | 用途 |
|---|---|---|
| 渲染异常捕获 | ErrorBoundary(类组件) | 捕获组件渲染异常 |
| 同步代码异常 | try-catch | 捕获缓存/表单/函数异常 |
| 网络异常处理 | Axios拦截器(interceptors) | 统一处理接口请求异常 |
| 列表性能优化 | FlatList(removeClippedSubviews等) | 提升列表渲染流畅度 |
| 组件懒加载 | React.lazy + Suspense | 减少启动加载压力 |
💡 二、核心知识点讲解(15分钟)
(保留原文档2.1-2.4内容,补充以下关键提醒)
💡 关键提醒:
- ErrorBoundary 仅能捕获类组件/函数组件的渲染异常,无法捕获异步代码(如接口请求)、事件处理函数中的异常,这类异常需用try-catch;
- 📱 鸿蒙开发板性能较弱,列表渲染数据量建议控制在5条以内,且禁用所有动效;
- 🔑 鸿蒙权限配置后需重新编译工程,真机需手动开启应用权限。
🛠️ 三、实操步骤(50分钟,完整可复制代码+关键标注)
🚨 3.1 步骤1:实现应用异常处理(20分钟)
🧩 3.1.1 封装ErrorBoundary异常捕获组件(修复原代码语法错误)
原代码问题:函数组件无法使用
static getDerivedStateFromError,需改为类组件
// src/components/ErrorBoundary.js
import React, { Component } from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
// 引入自定义Toast组件(补充完整Toast代码,确保依赖存在)
import CustomToast from './CustomToast';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
errorMsg: ''
};
}
// 捕获渲染异常,更新状态(类组件专属静态方法)
static getDerivedStateFromError(error) {
return {
hasError: true,
errorMsg: error.message || '未知渲染异常'
};
}
// 记录异常日志(可扩展为上传日志)
componentDidCatch(error, errorInfo) {
console.error('【RN鸿蒙】渲染异常详情:', {
error: error.message,
stack: error.stack,
info: errorInfo.componentStack,
time: new Date().toLocaleString()
});
}
// 重置异常状态
resetError = () => {
this.setState({ hasError: false, errorMsg: '' });
};
render() {
// 异常状态下显示降级UI
if (this.state.hasError) {
return (
<View style={styles.errorContainer}>
<Text style={styles.errorTitle}>应用出现异常</Text>
<Text style={styles.errorMsg}>{this.state.errorMsg}</Text>
<TouchableOpacity
style={styles.resetBtn}
onPress={this.resetError}
>
<Text style={styles.resetBtnText}>重新加载</Text>
</TouchableOpacity>
{/* 鸿蒙多终端适配:Toast提示字体/位置适配 */}
<CustomToast
visible={true}
type="error"
message={`渲染异常:${this.state.errorMsg}`}
onClose={this.resetError}
// 鸿蒙开发板适配:增大Toast字体
style={{ fontSize: 16 }}
/>
</View>
);
}
// 正常状态下渲染子组件
return this.props.children;
}
}
// 样式(重点标注鸿蒙多终端适配点)
const styles = StyleSheet.create({
errorContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
backgroundColor: '#fff'
},
errorTitle: {
fontSize: 20, // 📱 鸿蒙开发板适配:默认字体增大
fontWeight: 'bold',
marginBottom: 10,
color: '#e53935'
},
errorMsg: {
fontSize: 16, // 📱 鸿蒙开发板适配:字体增大
color: '#666',
marginBottom: 20,
textAlign: 'center'
},
resetBtn: {
backgroundColor: '#1890ff',
paddingHorizontal: 20,
paddingVertical: 10,
borderRadius: 8
},
resetBtnText: {
color: '#fff',
fontSize: 16 // 📱 鸿蒙开发板适配:按钮字体增大
}
});
export default ErrorBoundary;
🌐 3.1.2 全局引入ErrorBoundary(修改App.js)
// App.js
import React from 'react';
import { View, StyleSheet } from 'react-native';
import ErrorBoundary from './src/components/ErrorBoundary';
import HomePage from './src/pages/HomePage';
import FormPage from './src/pages/FormPage';
const App = () => {
return (
{/* 全局包裹ErrorBoundary,捕获所有页面渲染异常 */}
<ErrorBoundary>
<View style={styles.container}>
<HomePage />
{/* 其他页面组件 */}
</View>
</ErrorBoundary>
);
};
const styles = StyleSheet.create({
container: {
flex: 1
}
});
export default App;
📡 3.1.3 网络异常处理(Axios拦截器完整代码)
// src/api/request.js
import axios from 'axios';
import { View, Text } from 'react-native';
import CustomToast from '../components/CustomToast';
// 1. 创建axios实例(关键:定义service,修复原代码缺失问题)
const service = axios.create({
baseURL: 'http://your-api-base-url.com', // 替换为实际接口地址
timeout: 10000, // 📱 鸿蒙真机适配:超时时间延长至10s
headers: {
'Content-Type': 'application/json'
}
});
// 2. 请求拦截器(添加加载提示)
service.interceptors.request.use(
(config) => {
// 可添加加载中Toast(鸿蒙适配:简化加载提示)
CustomToast.show({
visible: true,
type: 'loading',
message: '请求中...',
style: { fontSize: 14 } // 📱 开发板适配
});
return config;
},
(error) => {
CustomToast.show({
visible: true,
type: 'error',
message: '请求参数异常',
style: { fontSize: 14 }
});
return Promise.reject(error);
}
);
// 3. 响应拦截器(统一处理网络异常)
service.interceptors.response.use(
(response) => {
// 关闭加载提示
CustomToast.show({ visible: false });
return response.data;
},
(error) => {
// 关闭加载提示
CustomToast.show({ visible: false });
// 分类处理网络异常
let errorMsg = '';
if (!error.response) {
errorMsg = '网络异常,请检查网络连接'; // 断网/超时
} else if (error.response.status === 404) {
errorMsg = '接口不存在,请检查地址';
} else if (error.response.status === 500) {
errorMsg = '服务器异常,请稍后重试';
} else if (error.response.status === 401) {
errorMsg = '登录失效,请重新登录';
} else {
errorMsg = `请求失败:${error.message || '未知错误'}`;
}
// 记录异常日志
console.error('【RN鸿蒙】网络异常:', {
url: error.config?.url,
method: error.config?.method,
status: error.response?.status,
message: errorMsg,
time: new Date().toLocaleString()
});
// 📱 鸿蒙多终端适配:异常提示样式
CustomToast.show({
visible: true,
type: 'error',
message: errorMsg,
style: {
fontSize: 16, // 📱 开发板字体增大
padding: 10, // 避免提示框遮挡
position: 'bottom' // 📱 真机/开发板:底部显示,不遮挡核心操作
}
});
// 📱 鸿蒙适配:添加请求重试(最多2次)
const { config } = error;
if (!config || !config.retryCount) {
config.retryCount = 0;
}
if (config.retryCount < 2) {
config.retryCount += 1;
const delay = new Promise((resolve) => {
setTimeout(resolve, 1000); // 延迟1s重试
});
return delay.then(() => service(config));
}
return Promise.reject(error);
}
);
export default service;
🗂️ 3.1.4 缓存异常处理(storage.js完整代码)
// src/utils/storage.js
import AsyncStorage from '@react-native-async-storage/async-storage';
import CustomToast from '../components/CustomToast';
/**
* 读取缓存(带异常捕获)
* @param {string} key 缓存键名
* @returns {Promise<any>} 缓存值
*/
export const getStorage = async (key) => {
try {
if (!key) {
throw new Error('缓存键名不能为空');
}
const value = await AsyncStorage.getItem(key);
// 解析JSON数据(处理格式异常)
if (value) {
if (value.startsWith('{') || value.startsWith('[')) {
return JSON.parse(value);
}
return value;
}
return null;
} catch (err) {
console.error('【RN鸿蒙】缓存读取失败:', {
key,
error: err.message,
time: new Date().toLocaleString()
});
// 📱 鸿蒙适配:异常提示
CustomToast.show({
visible: true,
type: 'error',
message: '缓存读取失败',
style: { fontSize: 16 }
});
return null;
}
};
/**
* 存储缓存(带异常捕获)
* @param {string} key 缓存键名
* @param {any} value 缓存值(自动序列化JSON)
* @param {number} expireTime 过期时间(毫秒,可选)
* @returns {Promise<boolean>} 是否成功
*/
export const setStorage = async (key, value, expireTime) => {
try {
if (!key) {
throw new Error('缓存键名不能为空');
}
// 添加过期时间(鸿蒙适配:便于后续清理)
const data = expireTime
? { value, expireTime: Date.now() + expireTime }
: value;
const storedValue = typeof data === 'object'
? JSON.stringify(data)
: data;
await AsyncStorage.setItem(key, storedValue);
return true;
} catch (err) {
console.error('【RN鸿蒙】缓存存储失败:', {
key,
error: err.message,
time: new Date().toLocaleString()
});
CustomToast.show({
visible: true,
type: 'error',
message: '缓存存储失败',
style: { fontSize: 16 }
});
return false;
}
};
/**
* 删除缓存(带异常捕获)
* @param {string} key 缓存键名
* @returns {Promise<boolean>} 是否成功
*/
export const removeStorage = async (key) => {
try {
if (!key) {
throw new Error('缓存键名不能为空');
}
await AsyncStorage.removeItem(key);
return true;
} catch (err) {
console.error('【RN鸿蒙】缓存删除失败:', {
key,
error: err.message,
time: new Date().toLocaleString()
});
CustomToast.show({
visible: true,
type: 'error',
message: '缓存删除失败',
style: { fontSize: 16 }
});
return false;
}
};
/**
* 清理过期缓存(鸿蒙性能优化核心)
* @returns {Promise<boolean>} 是否成功
*/
export const clearExpiredStorage = async () => {
try {
const keys = await AsyncStorage.getAllKeys();
const now = Date.now();
let clearedCount = 0;
for (const key of keys) {
const value = await getStorage(key);
// 仅清理带过期时间且已过期的缓存
if (value?.expireTime && value.expireTime < now) {
await removeStorage(key);
clearedCount++;
}
}
console.log(`【RN鸿蒙】清理过期缓存完成,共清理${clearedCount}条`);
CustomToast.show({
visible: true,
type: 'success',
message: `清理${clearedCount}条过期缓存`,
style: { fontSize: 16 }
});
return true;
} catch (err) {
console.error('【RN鸿蒙】清理过期缓存失败:', err.message);
CustomToast.show({
visible: true,
type: 'error',
message: '缓存清理失败',
style: { fontSize: 16 }
});
return false;
}
};
/**
* 清空所有缓存(谨慎使用)
* @returns {Promise<boolean>} 是否成功
*/
export const clearAllStorage = async () => {
try {
await AsyncStorage.clear();
console.log('【RN鸿蒙】所有缓存已清空');
CustomToast.show({
visible: true,
type: 'success',
message: '所有缓存已清空',
style: { fontSize: 16 }
});
return true;
} catch (err) {
console.error('【RN鸿蒙】清空缓存失败:', err.message);
CustomToast.show({
visible: true,
type: 'error',
message: '清空缓存失败',
style: { fontSize: 16 }
});
return false;
}
};
📝 3.1.5 代码错误处理(表单提交示例)
// src/pages/FormPage.js
import React, { useState } from 'react';
import { View, TextInput, TouchableOpacity, Text, StyleSheet } from 'react-native';
import { setStorage } from '../utils/storage';
import service from '../api/request';
import CustomToast from '../components/CustomToast';
const FormPage = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [phone, setPhone] = useState('');
// 表单验证
const validateForm = () => {
if (!name) {
CustomToast.show({ visible: true, type: 'warning', message: '姓名不能为空' });
return false;
}
if (!email.includes('@')) {
CustomToast.show({ visible: true, type: 'warning', message: '邮箱格式错误' });
return false;
}
return true;
};
// 表单提交(添加try-catch捕获异常)
const handleSubmit = async () => {
try {
const isValid = validateForm();
if (!isValid) return;
// 1. 提交接口
const res = await service.post('/user/add', { name, email, phone });
if (res.code === 200) {
// 2. 存储缓存(过期时间1小时)
await setStorage(`user_${res.data.id}`, res.data, 3600000);
CustomToast.show({
visible: true,
type: 'success',
message: '提交成功'
});
// 重置表单
setName('');
setEmail('');
setPhone('');
}
} catch (err) {
// 捕获所有代码/接口/缓存异常
console.error('【RN鸿蒙】表单提交异常:', err.message);
CustomToast.show({
visible: true,
type: 'error',
message: `提交失败:${err.message}`,
style: { fontSize: 16 } // 📱 鸿蒙适配
});
}
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="请输入姓名"
value={name}
onChangeText={setName}
placeholderTextColor="#999"
/>
<TextInput
style={styles.input}
placeholder="请输入邮箱"
value={email}
onChangeText={setEmail}
placeholderTextColor="#999"
keyboardType="email-address"
/>
<TextInput
style={styles.input}
placeholder="请输入电话"
value={phone}
onChangeText={setPhone}
placeholderTextColor="#999"
keyboardType="phone-pad"
/>
<TouchableOpacity style={styles.submitBtn} onPress={handleSubmit}>
<Text style={styles.submitBtnText}>提交</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#fff'
},
input: {
height: 50, // 📱 鸿蒙开发板适配:增大输入框高度
borderWidth: 1,
borderColor: '#eee',
borderRadius: 8,
paddingHorizontal: 15,
marginBottom: 15,
fontSize: 16 // 📱 开发板适配:增大字体
},
submitBtn: {
backgroundColor: '#1890ff',
height: 50, // 📱 开发板适配:增大按钮高度
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
marginTop: 10
},
submitBtnText: {
color: '#fff',
fontSize: 18 // 📱 开发板适配:增大按钮字体
}
});
export default FormPage;
✅ 3.1.6 异常处理验证步骤
- 🚨 故意修改列表组件代码(如
undefinedVariable),确认ErrorBoundary捕获并显示降级UI; - 📡 断开网络,提交表单,确认网络异常提示正常;
- 🗂️ 手动修改缓存数据(如存入非JSON字符串),调用
getStorage,确认缓存异常提示正常; - 📱 多终端验证:开发板/真机/模拟器的异常提示样式、位置均正常。
⚡ 3.2 步骤2:核心性能优化实战(15分钟)
📜 3.2.1 列表性能优化(FlatList完整代码)
// src/pages/HomePage.js
import React, { useState, useEffect, useCallback } from 'react';
import { View, Text, StyleSheet, FlatList, TouchableOpacity, Dimensions } from 'react-native';
import { getStorage, clearExpiredStorage } from '../utils/storage';
import service from '../api/request';
import CustomToast from '../components/CustomToast';
// 1. 提取列表项组件(React.memo避免重渲染)
const ListItem = React.memo(({ item }) => {
// 📱 鸿蒙开发板适配:简化列表项样式,删除冗余元素
return (
<View style={styles.listItem}>
<Text style={styles.listName}>{item.name}</Text>
{/* 📱 开发板适配:仅保留核心信息,减少渲染压力 */}
<Text style={styles.listInfo}>邮箱:{item.email}</Text>
</View>
);
});
// 2. 获取设备信息(鸿蒙多终端适配)
const { width, height } = Dimensions.get('window');
const isTablet = width > 768; // 📱 平板判断
const isDevBoard = height < 800; // 📱 开发板判断(DAYU200屏幕较小)
const HomePage = () => {
const [listData, setListData] = useState([]);
const [refreshing, setRefreshing] = useState(false);
// 3. 防抖处理:避免频繁刷新(性能优化核心)
const loadListData = useCallback(async (isRefresh = false) => {
try {
setRefreshing(true);
// 📱 开发板适配:限制数据量为5条
const limit = isDevBoard ? 5 : 10;
// 优先读取缓存,缓存无数据则请求接口
const cacheData = await getStorage('user_list');
if (cacheData && !isRefresh) {
setListData(cacheData.slice(0, limit));
setRefreshing(false);
return;
}
// 接口请求
const res = await service.get('/user/list', { params: { limit } });
setListData(res.data);
// 缓存数据(过期时间30分钟)
await setStorage('user_list', res.data, 1800000);
} catch (err) {
console.error('【RN鸿蒙】列表加载异常:', err.message);
CustomToast.show({
visible: true,
type: 'error',
message: '列表加载失败'
});
} finally {
setRefreshing(false);
}
}, []);
// 4. 启动优化:延迟加载列表数据(避免阻塞启动)
useEffect(() => {
// 清理过期缓存(性能优化:减少内存占用)
clearExpiredStorage();
// 延迟100ms加载,提升启动速度
const timer = setTimeout(() => loadListData(), 100);
// 组件卸载时清除定时器(避免内存泄漏)
return () => clearTimeout(timer);
}, [loadListData]);
// 5. 渲染列表项(平板双列布局适配)
const renderListItem = ({ item }) => {
if (isTablet) {
// 📱 平板双列布局
return (
<View style={styles.tabletListItem}>
<ListItem item={item} />
</View>
);
}
return <ListItem item={item} />;
};
return (
<View style={styles.container}>
<Text style={styles.title}>用户列表</Text>
{/* FlatList性能优化核心配置 */}
<FlatList
data={listData}
renderItem={renderListItem}
keyExtractor={(item) => item.id.toString()}
refreshing={refreshing}
onRefresh={() => loadListData(true)}
// ⚡ 性能优化:开启列表项复用(鸿蒙核心优化)
removeClippedSubviews={true}
// 📱 开发板适配:每次仅渲染5条
maxToRenderPerBatch={isDevBoard ? 5 : 8}
// 可视区域上下各渲染3屏(平衡流畅度与性能)
windowSize={3}
// 📱 禁用滚动动画(开发板适配)
scrollEnabled={!isDevBoard || listData.length > 5}
// 📱 平板适配:设置列数
numColumns={isTablet ? 2 : 1}
// 📱 开发板适配:禁用下拉刷新动画
refreshControl={
<View style={styles.refreshView}>
<Text>{refreshing ? '正在刷新...' : ''}</Text>
</View>
}
// 空数据提示
ListEmptyComponent={() => (
<Text style={styles.emptyText}>暂无数据</Text>
)}
/>
{/* 🗂️ 手动清理缓存按钮(性能优化扩展) */}
<TouchableOpacity style={styles.clearCacheBtn} onPress={clearExpiredStorage}>
<Text style={styles.clearCacheBtnText}>清理过期缓存</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 10,
backgroundColor: '#fff'
},
title: {
fontSize: isDevBoard ? 20 : 18, // 📱 开发板字体增大
fontWeight: 'bold',
marginBottom: 10,
textAlign: 'center'
},
listItem: {
height: isDevBoard ? 60 : 50, // 📱 开发板增大列表项高度(触控适配)
padding: 10,
borderBottomWidth: 1,
borderBottomColor: '#eee',
marginHorizontal: 5,
justifyContent: 'center'
},
listName: {
fontSize: isDevBoard ? 18 : 16, // 📱 开发板字体增大
fontWeight: 'bold'
},
listInfo: {
fontSize: isDevBoard ? 14 : 12,
color: '#666',
marginTop: 2
},
// 📱 平板双列布局样式
tabletListItem: {
flex: 1,
margin: 5
},
refreshView: {
height: 40,
justifyContent: 'center',
alignItems: 'center'
},
emptyText: {
textAlign: 'center',
marginTop: 20,
color: '#999',
fontSize: 16
},
clearCacheBtn: {
backgroundColor: '#f5f5f5',
height: 50,
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
marginTop: 10
},
clearCacheBtnText: {
color: '#1890ff',
fontSize: 16
}
});
export default HomePage;
🧩 3.2.2 组件懒加载(App.js修改)
// App.js
import React, { lazy, Suspense } from 'react';
import { View, Text, StyleSheet, ActivityIndicator } from 'react-native';
import ErrorBoundary from './src/components/ErrorBoundary';
import HomePage from './src/pages/HomePage';
// ⚡ 懒加载非核心组件(性能优化:启动时不加载)
const FormPage = lazy(() => import('./src/pages/FormPage'));
const SettingPage = lazy(() => import('./src/pages/SettingPage'));
const DetailPage = lazy(() => import('./src/pages/DetailPage'));
const App = () => {
return (
<ErrorBoundary>
<View style={styles.container}>
<HomePage />
{/* 懒加载组件包裹Suspense,添加加载占位符 */}
<Suspense
fallback={
<View style={styles.suspenseFallback}>
<ActivityIndicator size="large" color="#1890ff" />
<Text style={styles.loadingText}>页面加载中...</Text>
</View>
}
>
<FormPage />
{/* <SettingPage />
<DetailPage /> */}
</Suspense>
</View>
</ErrorBoundary>
);
};
const styles = StyleSheet.create({
container: {
flex: 1
},
suspenseFallback: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
loadingText: {
marginTop: 10,
fontSize: 16,
color: '#666'
}
});
export default App;
✅ 3.2.3 性能优化验证步骤
- ⚡ 运行工程,观察启动时间(优化后应<2s);
- 📜 滑动列表,确认无卡顿、掉帧(开发板需重点验证);
- 🗂️ 调用“清理过期缓存”按钮,查看控制台日志,确认缓存清理成功;
- 🔍 检查React DevTools(需安装),确认列表项无不必要的重渲染。
📱 3.3 步骤3:鸿蒙多终端性能适配与测试(10分钟)
🖥️ 3.3.1 开发板适配关键修改(已在上述代码中标注)
- 📜 简化列表项:仅保留核心信息,删除冗余文本/样式;
- 🖲️ 增大触控区域:列表项高度≥60px,按钮高度≥50px,字体≥16px;
- 📊 限制数据量:列表仅渲染5条数据;
- 🎬 禁用动效:下拉刷新替换为文本提示,禁用滚动动画;
- 🧹 内存优化:启动时清理过期缓存,限制缓存数据量。
📱 3.3.2 真机/平板适配关键修改
- 📱 平板双列布局:通过
Dimensions判断屏幕宽度,设置numColumns={2}; - 📡 网络适配:Axios超时时间延长至10s,添加2次重试机制;
- 🔑 权限适配:鸿蒙真机需手动开启“存储/网络”权限;
- 🎨 布局适配:平板端调整间距,避免内容溢出。
✅ 3.3.3 多终端测试用例
| 终端类型 | 测试重点 | 验收标准 |
|---|---|---|
| 🖥️ 模拟器 | 功能完整性、异常提示 | 所有功能正常,异常提示样式正确 |
| 📱 鸿蒙真机 | 启动速度、列表流畅度、网络 | 启动<2s,列表滑动无卡顿,网络请求稳定 |
| 🖥️ DAYU200开发板 | 触控体验、内存占用、稳定性 | 触控灵敏,内存占用<100MB,运行10分钟无崩溃 |
📦 3.4 步骤4:打包部署前置准备(5分钟)
⚙️ 3.4.1 工程配置检查
- package.json检查:
{
"name": "rnHarmonyDemo",
"version": "1.0.0",
"main": "index.js", // 🎯 入口文件必须正确
"scripts": {
"start": "react-native start",
"android": "react-native run-android",
"ios": "react-native run-ios",
"harmony": "react-native run-harmony" // 📱 鸿蒙运行命令
},
"dependencies": {
"@react-native-async-storage/async-storage": "^1.19.3",
"axios": "^1.5.1",
"react": "18.2.0",
"react-native": "0.72.7"
}
}
- app.json检查:
{
"name": "rnHarmonyDemo",
"displayName": "RN鸿蒙示例",
"version": "1.0.0",
"permissions": [
"internet",
"storage"
]
}
🧹 3.4.2 依赖清理(命令行)
# 清理未使用的依赖
npm prune
# 清理缓存
npm cache clean --force
# 删除临时文件
rm -rf node_modules/.cache
rm -rf android/build
rm -rf harmony/build
🔑 3.4.3 鸿蒙权限配置(config.json)
路径:
harmony/app/src/main/config.json
{
"app": {
"bundleName": "com.example.rnharmonydemo",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0"
},
"module": {
"package": "com.example.rnharmonydemo",
"name": ".MyApplication",
"mainAbility": ".MainAbility",
"deviceType": [
"phone",
"tablet",
"tv",
"wearable",
"liteWearable",
"smartVision"
],
"reqPermissions": [
{
"name": "ohos.permission.INTERNET", // 📡 网络权限
"reason": "用于接口请求",
"usedScene": {
"abilities": [".MainAbility"],
"when": "always"
}
},
{
"name": "ohos.permission.WRITE_USER_STORAGE", // 🗂️ 存储写权限
"reason": "用于缓存数据存储",
"usedScene": {
"abilities": [".MainAbility"],
"when": "always"
}
},
{
"name": "ohos.permission.READ_USER_STORAGE", // 🗂️ 存储读权限
"reason": "用于缓存数据读取",
"usedScene": {
"abilities": [".MainAbility"],
"when": "always"
}
}
],
"abilities": [
{
"name": ".MainAbility",
"srcPath": "MainAbility",
"description": "$string:mainability_description",
"icon": "$media:icon",
"label": "$string:app_name",
"type": "page",
"launchType": "standard"
}
]
}
}
✅ 3.4.4 前置准备验证
- 📦 运行
npm install,确认无依赖冲突; - 📱 运行
react-native run-harmony,确认应用正常启动,无权限报错; - 🧹 检查工程目录,确认
test目录、临时文件已删除。
❌ 四、常见问题与解决方案(10分钟)
| 问题现象 | 原因分析 | 解决方案 |
|---|---|---|
| 🚨 ErrorBoundary无法捕获异常 | 1. 函数组件使用static方法;2. 异步代码异常 | 1. 改为类组件;2. 异步代码添加try-catch |
| 📜 开发板列表仍卡顿 | 1. 数据量过大;2. 样式复杂 | 1. 限制数据量≤5条;2. 删除所有动效/冗余样式 |
| 🗂️ 缓存清理无效 | 缓存数据无expireTime字段 | 存储时添加expireTime,格式为时间戳 |
| 📱 真机提示“权限不足” | 1. config.json未配置;2. 未手动开启 | 1. 检查权限配置;2. 真机设置→应用→当前应用→手动开启存储/网络权限 |
| ⚡ 应用启动缓慢 | 1. 启动时同步加载组件;2. 依赖冗余 | 1. 非核心组件懒加载;2. 延迟加载列表数据;3. 清理冗余依赖 |
📝 五、课堂小结(5分钟)
🎯 核心要点回顾
- 异常处理 🚨:通过
ErrorBoundary捕获渲染异常、try-catch捕获同步异常、Axios拦截器捕获网络异常,核心是“捕获-提示-降级-日志”,适配鸿蒙多终端样式; - 性能优化 ⚡:列表优化(
removeClippedSubviews/memo)、组件懒加载、缓存清理是核心,开发板需“简化+降级”适配; - 打包前置 📦:重点检查工程配置、清理依赖、配置鸿蒙权限,确保打包无冲突。
✅ 六、课后任务(必做)
- 🛠️ 独立完成异常处理+性能优化全流程,验证多终端运行效果;
- 🚀 扩展功能:
- 📝 新增异常日志本地存储(写入文件);
- ⚡ 列表上拉加载更多添加防抖(延迟500ms);
- 🗂️ 设置页添加“手动清理所有缓存”按钮;
- 📱 完善适配:
- 🖥️ 开发板添加“加载中”文本提示(无动效);
- 📱 平板端优化双列布局间距与样式;
- 📚 预习:RN鸿蒙应用打包流程、签名配置相关知识。
🚀 实操遇到问题可留言,下一节课将讲解应用打包部署,完成从0到1的开发闭环!
欢迎加入开源鸿蒙跨平台社区,https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)