【HarmonyOS】React Native实战项目+Redux Toolkit状态管理
Redux Toolkit(简称RTK)是Redux官方推荐的现代化状态管理工具,通过**切片(Slice)机制**大幅简化了状态管理代码的编写。在OpenHarmony平台应用中,RTK不仅能提升开发效率,更能通过特定的平台优化策略改善应用性能。
·
【HarmonyOS】React Native实战项目+Redux Toolkit状态管理

🌟 感谢陪伴~ 小白博主在线求友
🌿 跟着小白学Linux/Java/Python
📖 专栏汇总:
《Linux》专栏 | 《Java》专栏 | 《Python》专栏

欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
一、Redux Toolkit在OpenHarmony平台的适配价值
Redux Toolkit(简称RTK)是Redux官方推荐的现代化状态管理工具,通过切片(Slice)机制大幅简化了状态管理代码的编写。在OpenHarmony平台应用中,RTK不仅能提升开发效率,更能通过特定的平台优化策略改善应用性能。
1.1 传统Redux与RTK对比
┌─────────────────────────────────────────────────────────────┐
│ Redux演进:从传统到Toolkit │
├─────────────────────────────────────────────────────────────┤
│ │
│ 传统Redux开发流程 Redux Toolkit开发流程 │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 定义Action │ │ 创建Slice │ │
│ │ Types │ │ (一步到位) │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ ┌──────▼───────┐ ┌──────▼───────┐ │
│ │ 编写Action │ │ 自动生成 │ │
│ │ Creators │ │ Actions │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ ┌──────▼───────┐ ┌──────▼───────┐ │
│ │ 定义Reducer │ │ 集成Store │ │
│ │ Switch Case │ │ (完成) │ │
│ └──────┬───────┘ └──────────────┘ │
│ │ │
│ ┌──────▼───────┐ │
│ │ 手动组合 │ 代码量减少 ~60% │
│ │ combineReducers│ 类型安全 自动推断 │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
1.2 OpenHarmony平台适配优势
| 特性 | 传统Redux | Redux Toolkit | OpenHarmony收益 |
|---|---|---|---|
| 代码体积 | ~500行基础代码 | ~200行 | 减少应用包体积,适配鸿蒙存储限制 |
| 异步处理 | 需redux-thunk | 内置createAsyncThunk | 优化鸿蒙任务调度机制 |
| 类型定义 | 手动维护 | 自动推断 | 提升TS在鸿蒙环境开发体验 |
| 不可变更新 | 手动展开运算符 | 内置Immer | 减少运行时计算负担 |
| 开发效率 | 中等 | 高 | 加速鸿蒙应用迭代周期 |
1.3 鸿蒙应用状态管理架构
┌─────────────────────────────────────────────────────────────┐
│ OpenHarmony应用状态管理架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ React Native UI组件 │ │
│ │ • useSelector(state => selector) │ │
│ │ • useDispatch(actionCreator) │ │
│ └──────────────────┬──────────────────────────┘ │
│ │ │
│ ┌──────────────────▼──────────────────────────┐ │
│ │ Redux Toolkit Slice层 │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │UserSlice│ │AppSlice │ │APISlice │ │ │
│ │ └────┬────┘ └────┬────┘ └────┬────┘ │ │
│ └───────┼──────────┼──────────┼───────────┘ │
│ │ │ │ │
│ ┌───────▼──────────▼──────────▼───────────┐ │
│ │ Redux Store (configureStore) │ │
│ │ • Redux DevTools │ │
│ │ • Immer (不可变更新) │ │
│ │ • Redux Thunk (异步处理) │ │
│ └───────┬──────────────────────────────────┘ │
│ │ │
│ ┌───────▼───────────────────────────────────┐ │
│ │ 持久化层 (OpenHarmony适配) │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ ohos.data.relationalStore │ │ │
│ │ │ (鸿蒙关系型数据库) │ │ │
│ │ └─────────────────────────────────┘ │ │
│ └────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
二、Slice配置核心概念
2.1 Slice结构解析
Redux Toolkit的Slice是一个完整的状态管理单元,包含:
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
/**
* 用户配置Slice - OpenHarmony平台优化版
*/
interface UserSettings {
theme: 'light' | 'dark';
fontSize: number;
language: string;
lastSync: number; // 鸿蒙设备时间戳
}
interface UserState {
settings: UserSettings;
loading: boolean;
error: string | null;
}
const initialState: UserState = {
settings: {
theme: 'light',
fontSize: 14,
language: 'zh-CN',
lastSync: 0,
},
loading: false,
error: null,
};
const userSlice = createSlice({
// 命名空间:自动生成action类型前缀
name: 'user',
// 初始状态
initialState,
// 同步reducers - 自动生成action creators
reducers: {
/**
* 切换主题
* Immer自动处理不可变更新
*/
toggleTheme(state) {
state.settings.theme =
state.settings.theme === 'light' ? 'dark' : 'light';
state.settings.lastSync = Date.now();
},
/**
* 设置字体大小
*/
setFontSize(state, action: PayloadAction<number>) {
const size = Math.max(12, Math.min(24, action.payload));
state.settings.fontSize = size;
state.settings.lastSync = Date.now();
},
/**
* 设置语言
*/
setLanguage(state, action: PayloadAction<string>) {
state.settings.language = action.payload;
state.settings.lastSync = Date.now();
},
/**
* 重置设置
*/
resetSettings(state) {
state.settings = { ...initialState.settings };
},
},
// 异步reducers - 使用extraReducers处理
extraReducers: (builder) => {
builder
// 加载设置异步操作
.addCase(loadSettings.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(loadSettings.fulfilled, (state, action) => {
state.loading = false;
state.settings = action.payload;
})
.addCase(loadSettings.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message || '加载失败';
});
},
});
// 导出自动生成的action creators
export const {
toggleTheme,
setFontSize,
setLanguage,
resetSettings,
} = userSlice.actions;
// 导出reducer
export default userSlice.reducer;
2.2 异步操作处理(createAsyncThunk)
import { createAsyncThunk } from '@reduxjs/toolkit';
import { ohosData } from '@ohos.data.relationalStore';
/**
* 异步加载用户设置
* 使用OpenHarmony关系型数据库
*/
export const loadSettings = createAsyncThunk(
'user/loadSettings',
async (userId: string, { rejectWithValue }) => {
try {
// 获取鸿蒙数据库存储实例
const store = await ohosData.getRdbStore({
name: 'UserSettings.db',
securityLevel: ohosData.SecurityLevel.S1,
});
// 查询用户设置
const predicates = new ohosData.RdbPredicates('UserSettings');
predicates.equalTo('userId', userId);
const resultSet = await store.query('UserSettings', predicates);
if (resultSet.goToFirstRow()) {
return {
theme: resultSet.getString(resultSet.getColumnIndex('theme')),
fontSize: resultSet.getLong(resultSet.getColumnIndex('fontSize')),
language: resultSet.getString(resultSet.getColumnIndex('language')),
lastSync: resultSet.getLong(resultSet.getColumnIndex('lastSync')),
};
}
// 返回默认设置
return initialState.settings;
} catch (error) {
return rejectWithValue('加载设置失败');
}
}
);
/**
* 保存用户设置到OpenHarmony数据库
*/
export const saveSettings = createAsyncThunk(
'user/saveSettings',
async (settings: UserSettings, { rejectWithValue }) => {
try {
const store = await ohosData.getRdbStore({
name: 'UserSettings.db',
securityLevel: ohosData.SecurityLevel.S1,
});
const valueBucket = {
'userId': 'default',
'theme': settings.theme,
'fontSize': settings.fontSize,
'language': settings.language,
'lastSync': Date.now(),
};
await store.insert('UserSettings', valueBucket);
return settings;
} catch (error) {
return rejectWithValue('保存设置失败');
}
}
);
2.3 Store配置与持久化
import { configureStore } from '@reduxjs/toolkit';
import { combineReducers } from '@reduxjs/toolkit';
import userReducer from './slices/userSlice';
import appReducer from './slices/appSlice';
/**
* Redux Store配置 - OpenHarmony平台优化版
*/
const rootReducer = combineReducers({
user: userReducer,
app: appReducer,
});
export const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
// 忽略OpenHarmony API调用
ignoredActions: ['user/loadSettings/fulfilled'],
},
}),
devTools: __DEV__,
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
/**
* OpenHarmony持久化中间件
*/
export const createPersistenceMiddleware = (store: any) => (
next: any
) => (action: any) => {
const result = next(action);
// 防抖保存:300ms内只保存一次
if (persistenceTimeout) {
clearTimeout(persistenceTimeout);
}
persistenceTimeout = setTimeout(() => {
const state = store.getState();
saveToHarmonyStorage(state);
}, 300);
return result;
};
let persistenceTimeout: NodeJS.Timeout | null = null;
/**
* 保存状态到OpenHarmony存储
*/
async function saveToHarmonyStorage(state: RootState) {
try {
const preferences = await ohosData.getPreferences(
getContext(),
'redux_state'
);
await preferences.put('user_settings', state.user.settings);
await preferences.flush();
console.log('[Persistence] State saved to OpenHarmony storage');
} catch (error) {
console.error('[Persistence] Failed to save state:', error);
}
}
三、OpenHarmony平台专项优化
3.1 异步操作适配策略
┌─────────────────────────────────────────────────────────┐
│ OpenHarmony异步任务处理流程 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌────────────┐ ┌────────────┐ ┌──────────┐ │
│ │ UI交互 │ │ Dispatch │ │ 鸿蒙API │ │
│ │ 触发Action │────▶│ AsyncThunk │────▶│ 调用 │ │
│ └────────────┘ └─────┬──────┘ └────┬─────┘ │
│ │ │ │
│ ┌──────▼──────┐ │ │
│ │ pending状态 │ │ │
│ │ loading=true │ │ │
│ └─────────────┘ │ │
│ │ │ │
│ ┌──────▼──────┐ │ │
│ │ 任务执行 │ │ │
│ │ 鸿蒙线程池 │ │ │
│ └──────┬──────┘ │ │
│ │ │ │
│ ┌────────────┴────────────┐ │ │
│ │ │ │ │
│ ┌─────▼─────┐ ┌─────▼─────▼─────┐ │
│ │ fulfilled │ │ rejected │ │
│ │ 更新状态 │ │ 记录错误信息 │ │
│ └───────────┘ └────────────────┘ │
└─────────────────────────────────────────────────────────┘
3.2 持久化存储方案对比
| 存储方式 | OpenHarmony API | 适用场景 | 性能 | 容量限制 |
|---|---|---|---|---|
| Preferences | ohos.data.preferences |
简单键值对 | 高 | 1MB |
| 关系型数据库 | ohos.data.relationalStore |
结构化数据 | 最高 | 100MB |
| 分布式数据 | ohos.data.distributedData |
跨设备同步 | 中 | 50MB |
推荐配置:
- 用户设置 → Preferences(快速读写)
- 应用数据 → RelationalStore(复杂查询)
- 跨设备数据 → DistributedData(自动同步)
3.3 内存管理优化
/**
* OpenHarmony内存优化Slice
*/
import { createSlice, createEntityAdapter } from '@reduxjs/toolkit';
/**
* 实体适配器 - 高效管理列表数据
* 自动生成ID映射和选择器
*/
const listEntityAdapter = createEntityAdapter<ListItem>({
// 自定义ID选择
selectId: (item) => item.id,
// 排序比较函数
sortComparer: (a, b) => a.timestamp - b.timestamp,
});
/**
* 列表Slice - 内存优化版
*/
const listSlice = createSlice({
name: 'list',
initialState: listEntityAdapter.getInitialState({
loading: false,
error: null,
// 分页元数据
pagination: {
page: 1,
hasMore: true,
},
}),
reducers: {
/**
* 添加单个项目(使用实体适配器)
*/
addOne: listEntityAdapter.addOne,
/**
* 批量添加(去重)
*/
addMany: listEntityAdapter.upsertMany,
/**
* 移除项目
*/
removeOne: listEntityAdapter.removeOne,
/**
* 更新项目
*/
updateOne: listEntityAdapter.updateOne,
/**
* 清空列表(保留分页信息)
*/
clearList: (state) => {
listEntityAdapter.removeAll(state);
state.pagination.page = 1;
state.pagination.hasMore = true;
},
},
extraReducers: (builder) => {
builder
.addCase(fetchList.pending, (state) => {
state.loading = true;
})
.addCase(fetchList.fulfilled, (state, action) => {
state.loading = false;
// 使用实体适配器的智能合并
listEntityAdapter.upsertMany(state, action.payload.items);
state.pagination = action.payload.pagination;
});
},
});
// 导出选择器
export const {
selectAll,
selectById,
selectIds,
} = listEntityAdapter.getSelectors();
export default listSlice.reducer;
四、完整应用示例
/**
* ReduxToolkitDemo - Redux Toolkit完整演示
*/
import React, { useState } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ScrollView } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import {
toggleTheme,
setFontSize,
resetSettings,
loadSettings,
} from '../store/slices/userSlice';
import type { RootState } from '../store';
export function ReduxToolkitDemo({ onBack }: { onBack: () => void }) {
const dispatch = useDispatch();
const userState = useSelector((state: RootState) => state.user);
const [fontSizeInput, setFontSizeInput] = useState('14');
// 动态样式计算
const isDark = userState.settings.theme === 'dark';
const dynamicStyles = {
container: {
backgroundColor: isDark ? '#1a1a1a' : '#f5f5f5',
},
content: {
backgroundColor: isDark ? '#1a1a1a' : '#f5f5f5',
},
card: {
backgroundColor: isDark ? '#2a2a2a' : '#ffffff',
},
text: {
color: isDark ? '#ffffff' : '#333333',
},
code: {
color: isDark ? '#d4d4d4' : '#1e1e1e',
backgroundColor: isDark ? '#1e1e1e' : '#f5f5f5',
},
};
const handleFontSizeChange = () => {
const size = parseInt(fontSizeInput, 10);
if (!isNaN(size) && size >= 12 && size <= 24) {
dispatch(setFontSize(size));
}
};
return (
<View style={[styles.container, dynamicStyles.container]}>
<View style={[styles.header, isDark && styles.headerDark]}>
<TouchableOpacity onPress={onBack}>
<Text style={styles.backBtn}>←</Text>
</TouchableOpacity>
<View style={styles.headerContent}>
<Text style={styles.headerTitle}>Redux Toolkit</Text>
<Text style={styles.headerSubtitle}>切片配置演示</Text>
</View>
</View>
<ScrollView style={[styles.content, dynamicStyles.content]}>
{/* 当前状态 */}
<View style={[styles.card, dynamicStyles.card]}>
<Text style={[styles.cardTitle, dynamicStyles.text]}>📊 当前状态</Text>
<View style={styles.stateDisplay}>
<View style={styles.stateRow}>
<Text style={styles.stateLabel}>theme:</Text>
<Text style={[styles.code, dynamicStyles.code]}>
"{userState.settings.theme}"
</Text>
<View
style={[
styles.themeDot,
isDark && styles.themeDotDark,
]}
/>
</View>
<View style={styles.stateRow}>
<Text style={styles.stateLabel}>fontSize:</Text>
<Text style={[styles.code, dynamicStyles.code]}>
{userState.settings.fontSize}px
</Text>
</View>
<View style={styles.stateRow}>
<Text style={styles.stateLabel}>loading:</Text>
<Text style={[styles.code, dynamicStyles.code]}>
{String(userState.loading)}
</Text>
</View>
</View>
</View>
{/* Actions */}
<View style={[styles.card, dynamicStyles.card]}>
<Text style={[styles.cardTitle, dynamicStyles.text]}>⚡ Dispatch Actions</Text>
<View style={styles.actionGroup}>
<Text style={[styles.actionLabel, dynamicStyles.text]}>toggleTheme()</Text>
<View style={styles.buttonRow}>
<TouchableOpacity
style={[
styles.themeBtn,
styles.lightBtn,
!isDark && styles.themeBtnActive,
]}
onPress={() => dispatch(toggleTheme())}
>
<Text style={styles.lightBtnText}>☀️ Light</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.themeBtn,
styles.darkBtn,
isDark && styles.themeBtnActive,
]}
onPress={() => dispatch(toggleTheme())}
>
<Text style={styles.darkBtnText}>🌙 Dark</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.actionGroup}>
<Text style={[styles.actionLabel, dynamicStyles.text]}>setFontSize(size)</Text>
<View style={styles.inputRow}>
<TextInput
style={[styles.input, dynamicStyles.code]}
value={fontSizeInput}
onChangeText={setFontSizeInput}
keyboardType="number-pad"
placeholder="12-24"
/>
<TouchableOpacity
style={styles.applyBtn}
onPress={handleFontSizeChange}
>
<Text style={styles.applyBtnText}>应用</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.actionGroup}>
<Text style={[styles.actionLabel, dynamicStyles.text]}>loadSettings() - 异步</Text>
<TouchableOpacity
style={[styles.asyncBtn, userState.loading && styles.asyncBtnDisabled]}
onPress={() => dispatch(loadSettings('default') as any)}
disabled={userState.loading}
>
<Text style={styles.asyncBtnText}>
{userState.loading ? '加载中...' : '🔄 加载设置'}
</Text>
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.resetBtn}
onPress={() => dispatch(resetSettings())}
>
<Text style={styles.resetBtnText}>🔄 重置状态</Text>
</TouchableOpacity>
</View>
{/* 代码示例 */}
<View style={[styles.card, dynamicStyles.card]}>
<Text style={[styles.cardTitle, dynamicStyles.text]}>📄 Slice代码</Text>
<View style={[styles.codeBlock, dynamicStyles.code]}>
<Text style={[styles.codeText, { color: '#9cdcfe' }]}>
{`const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
toggleTheme(state) {
state.theme = state.theme === 'light'
? 'dark' : 'light'
}
}
})`}
</Text>
</View>
</View>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#f5f5f5' },
header: {
flexDirection: 'row',
alignItems: 'center',
padding: 16,
paddingTop: 48,
backgroundColor: '#764ABC',
},
headerDark: { backgroundColor: '#5a3a9e' },
backBtn: {
width: 40, height: 40,
color: '#fff', fontSize: 24,
textAlign: 'center',
},
headerContent: { flex: 1 },
headerTitle: {
fontSize: 20, fontWeight: '700',
color: '#fff',
},
headerSubtitle: {
fontSize: 14, color: '#fff',
opacity: 0.9, marginTop: 2,
},
content: { flex: 1, padding: 16 },
card: {
backgroundColor: '#fff',
borderRadius: 12,
padding: 16,
marginBottom: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
cardTitle: {
fontSize: 18, fontWeight: '700',
color: '#333', marginBottom: 16,
},
stateDisplay: {
backgroundColor: '#1e1e1e',
borderRadius: 8,
padding: 16,
},
stateRow: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 8,
},
stateLabel: {
fontSize: 13, color: '#9cdcfe',
marginRight: 8, width: 80,
},
code: {
fontSize: 13, fontFamily: 'monospace',
backgroundColor: '#1e1e1e',
color: '#d4d4d4',
paddingHorizontal: 8,
paddingVertical: 4,
borderRadius: 4,
},
themeDot: {
width: 12, height: 12,
borderRadius: 6,
backgroundColor: '#f0f0f0',
borderWidth: 1,
borderColor: '#666',
},
themeDotDark: {
backgroundColor: '#333',
borderColor: '#999',
},
actionGroup: {
marginBottom: 16,
},
actionLabel: {
fontSize: 14, fontWeight: '500',
color: '#666', marginBottom: 10,
},
buttonRow: {
flexDirection: 'row',
gap: 12,
},
themeBtn: {
flex: 1, padding: 14,
borderRadius: 8,
alignItems: 'center',
},
themeBtnActive: {
borderWidth: 2,
borderColor: '#764ABC',
},
lightBtn: { backgroundColor: '#f5f5f5' },
lightBtnText: {
fontSize: 14, fontWeight: '600',
color: '#333',
},
darkBtn: { backgroundColor: '#333' },
darkBtnText: {
fontSize: 14, fontWeight: '600',
color: '#fff',
},
inputRow: {
flexDirection: 'row',
gap: 10,
},
input: {
flex: 1, height: 48,
borderRadius: 8,
paddingHorizontal: 16,
fontSize: 14,
borderWidth: 1,
borderColor: '#e0e0e0',
},
applyBtn: {
paddingHorizontal: 20,
backgroundColor: '#764ABC',
borderRadius: 8,
justifyContent: 'center',
},
applyBtnText: {
fontSize: 14, fontWeight: '600',
color: '#fff',
},
asyncBtn: {
padding: 14,
backgroundColor: '#03A9F4',
borderRadius: 8,
alignItems: 'center',
},
asyncBtnDisabled: {
backgroundColor: '#B0BEC5',
},
asyncBtnText: {
fontSize: 14, fontWeight: '600',
color: '#fff',
},
resetBtn: {
padding: 14,
backgroundColor: '#f5f5f5',
borderWidth: 1,
borderColor: '#e0e0e0',
borderRadius: 8,
alignItems: 'center',
},
resetBtnText: {
fontSize: 14, fontWeight: '600',
color: '#666',
},
codeBlock: {
borderRadius: 8,
padding: 16,
},
codeText: {
fontSize: 12,
fontFamily: 'monospace',
lineHeight: 18,
},
});
五、项目源码
完整项目Demo: AtomGitDemos
技术栈:
- React Native 0.72.5
- OpenHarmony 6.0.0 (API 20)
- Redux Toolkit 1.9+
- TypeScript 4.8.4
社区支持: 开源鸿蒙跨平台社区
📕个人领域 :Linux/C++/java/AI
🚀 个人主页 :有点流鼻涕 · CSDN
💬 座右铭 : “向光而行,沐光而生。”

更多推荐



所有评论(0)