在React Native中,实现本地数据存储有多种方式,每种方式有其特定的使用场景和优缺点。以下是几种常见的本地数据存储方式:
- AsyncStorage
AsyncStorage是React Native提供的一个简单的、异步的、持久化的、key-value存储系统。它非常适合存储小的数据片段,例如用户的登录令牌、偏好设置等。
使用示例:
importAsyncStoragefrom'@react-native-async-storage/async-storage';// 存储数据AsyncStorage.setItem('key','value').then(()=>{console.log('Data saved');}).catch(error=>{console.error('Error saving data',error);});// 读取数据AsyncStorage.getItem('key').then(value=>{console.log('Data retrieved:',value);}).catch(error=>{console.error('Error retrieving data',error);});- SQLite 数据库
对于需要存储大量结构化数据的应用,可以使用SQLite数据库。React Native提供了react-native-sqlite-storage这样的库来操作SQLite数据库。
安装库:
npminstall--save react-native-sqlite-storage使用示例:
importSQLitefrom'react-native-sqlite-storage';SQLite.DEBUG(true);// 启用调试模式(可选)vardb=SQLite.openDatabase({name:'mydb.db',location:'default'},()=>{console.log('Database opened');},(error)=>{console.error('Error opening database:',error);});db.transaction(tx=>{tx.executeSql('CREATE TABLE IF NOT EXISTS MyTable (id INTEGER PRIMARY KEY, data TEXT)');tx.executeSql('INSERT INTO MyTable (data) VALUES (?)',['test']);});- Realm Database
Realm是一个移动数据库,它提供了一个面向对象的编程接口,使得操作数据库更加简单和直观。它支持Harmony、Harmony和React Native。
安装库:
npminstallrealm @realm/react --save使用示例:
importRealmfrom'realm';import{useRealm}from'@realm/react';// 用于React hooks的集成constMySchema={name:'MyObject',properties:{id:'int',data:'string'},primaryKey:'id'};constrealm=newRealm({schema:[MySchema]});// 初始化Realm实例,并定义schemaconstrealmInstance=useRealm(realm);// 在React组件中使用Realm实例(如果你使用hooks)- Redux Persist 或其他状态管理库结合 LocalStorage 或 AsyncStorage
如果你的应用使用了Redux进行状态管理,可以使用redux-persist库结合AsyncStorage或LocalStorage来持久化Redux的状态。这样,应用的状态就可以在应用重启后恢复。
安装库:
npminstallredux-persist @react-native-async-storage/async-storage --save // 注意:@react-native-async-storage/async-storage 是 AsyncStorage 的替代品,用于React Native0.60及以上版本。如果你使用的是旧版本,请使用 @react-native-community/async-storage。配置示例:
import{persistStore,persistReducer}from'redux-persist';importstoragefrom'@react-native-async-storage/async-storage';// 或者使用 @react-native-community/async-storage 对于旧版本React Native。import{createStore}from'redux';importrootReducerfrom'./reducers';// 你的reducer文件路径。constpersistConfig={key:'root',// 存储的key值。可以根据需要更改。storage,// 使用AsyncStorage作为存储介质。也可以使用其他支持的存储方式。例如:localStorage。对于React Native,推荐使用AsyncStorage。 如果你使用的是旧版本React Native,请使用AsyncStorage的社区版本。 例如:import AsyncStorage from '@react-native-community/async-storage'; 并且将storage设置为 AsyncStorage。 而不是'@react-native-async-storage/async-storage'。 这是因为'@react-native-async-storage/async-storage'是为React Native真实案例演示代码:
// app.tsximportReact,{useState}from'react';import{View,Text,StyleSheet,TouchableOpacity,TextInput,ScrollView,Alert,Image}from'react-native';constApp=()=>{const[key,setKey]=useState('');const[value,setValue]=useState('');const[items,setItems]=useState<Record<string,string>>({});const[editMode,setEditMode]=useState(false);// Base64 iconsconsticons={save:'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiM0Mjg1RjQiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMTkgMjFINGEyIDIgMCAwIDEtMi0yVjVhMiAyIDAgMCAxIDItMmg3Ij48L3BhdGg+PHBvbHlsaW5lIHBvaW50cz0iMTcgMiA5LjUgMiA3IDcgMTcgNyAxNyAyIj48L3BvbHlsaW5lPjxsaW5lIHgxPSI5IiB5MT0iOSIgeDI9IjE1IiB5Mj0iOSI+PC9saW5lPjxsaW5lIHgxPSI5IiB5MT0iMTMiIHgyPSIxNSIgeTI9IjEzIj48L2xpbmU+PGxpbmUgeDE9IjkiIHkxPSIxNyIgeDI9IjE1IiB5Mj0iMTciPjwvbGluZT48L3N2Zz4=',delete:'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNFRTQ0M0EiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMTkgNlY1YTIgMiAwIDAgMC0yLTJIN2EyIDIgMCAwIDAtMiAydjEiPjwvcGF0aD48bGluZSB4MT0iOCIgeTE9IjkiIHgyPSIxNiIgeTI9IjkiPjwvbGluZT48cGF0aCBkPSJNMTkgNlYyMGEyIDIgMCAwIDEtMiAyaC04YTIgMiAwIDAgMS0yLTJWNiI+PC9wYXRoPjxyZWN0IHg9IjkiIHk9IjYiIHdpZHRoPSIxMiIgaGVpZ2h0PSIxOCIgcng9IjIiIHJ5PSIyIj48L3JlY3Q+PC9zdmc+',edit:'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiM0Mjg1RjQiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMTcgM0EyIDIgMCAwIDAgMTUuNTg2IDMuNDY0TDMuNTg2IDE1LjQ2NEEyIDIgMCAwIDAgMyAyMWgyLjVhMSAxIDAgMCAwIC43MDctLjI5M2wxMi0xMkExIDIgMCAwIDAgMTcgM3oiPjwvcGF0aD48L3N2Zz4=',clear:'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiM5OTkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMTggNiA2IDE4Ij48L3BhdGg+PHBhdGggZD0iTTE4IDE4IDYgNiI+PC9wYXRoPjwvc3ZnPg=='};constsaveData=()=>{if(!key.trim()||!value.trim()){Alert.alert('错误','键和值都不能为空');return;}setItems(prev=>({...prev,[key]:value}));setKey('');setValue('');Alert.alert('成功','数据已保存');};constdeleteItem=(itemKey:string)=>{setItems(prev=>{constnewItems={...prev};deletenewItems[itemKey];returnnewItems;});Alert.alert('成功','数据已删除');};constclearAll=()=>{setItems({});Alert.alert('成功','所有数据已清空');};constloadItem=(itemKey:string,itemValue:string)=>{if(editMode){setKey(itemKey);setValue(itemValue);}};return(<ScrollView style={styles.container}><View style={styles.header}><Text style={styles.title}>本地数据存储</Text><Text style={styles.subtitle}>简易键值对存储系统</Text></View><View style={styles.formContainer}><View style={styles.inputGroup}><Text style={styles.label}>键(Key)</Text><TextInput style={styles.input}value={key}onChangeText={setKey}placeholder="输入键名"/></View><View style={styles.inputGroup}><Text style={styles.label}>值(Value)</Text><TextInput style={[styles.input,styles.textArea]}value={value}onChangeText={setValue}placeholder="输入值"multiline numberOfLines={3}/></View><View style={styles.buttonRow}><TouchableOpacity style={[styles.button,styles.saveButton]}onPress={saveData}><Image source={{uri:icons.save}}style={styles.buttonIcon}/><Text style={styles.buttonText}>保存</Text></TouchableOpacity><TouchableOpacity style={[styles.button,styles.editButton]}onPress={()=>setEditMode(!editMode)}><Image source={{uri:icons.edit}}style={styles.buttonIcon}/><Text style={styles.buttonText}>{editMode?'取消编辑':'编辑模式'}</Text></TouchableOpacity></View></View><View style={styles.dataContainer}><View style={styles.dataHeader}><Text style={styles.dataTitle}>已存储的数据</Text>{Object.keys(items).length>0&&(<TouchableOpacity style={styles.clearButton}onPress={clearAll}><Image source={{uri:icons.clear}}style={styles.clearIcon}/><Text style={styles.clearText}>清空</Text></TouchableOpacity>)}</View>{Object.keys(items).length===0?(<View style={styles.emptyContainer}><Text style={styles.emptyText}>暂无数据</Text></View>):(<View style={styles.dataList}>{Object.entries(items).map(([itemKey,itemValue])=>(<View key={itemKey}style={styles.dataItem}><TouchableOpacity style={styles.dataContent}onPress={()=>loadItem(itemKey,itemValue)}><Text style={styles.itemKey}>{itemKey}</Text><Text style={styles.itemValue}numberOfLines={2}>{itemValue}</Text></TouchableOpacity><TouchableOpacity style={styles.deleteButton}onPress={()=>deleteItem(itemKey)}><Image source={{uri:icons.delete}}style={styles.deleteIcon}/></TouchableOpacity></View>))}</View>)}</View></ScrollView>);};conststyles=StyleSheet.create({container:{flex:1,backgroundColor:'#f5f8fa',padding:20},header:{alignItems:'center',marginBottom:30,paddingTop:20},title:{fontSize:26,fontWeight:'bold',color:'#2c3e50'},subtitle:{fontSize:14,color:'#7f8c8d',marginTop:5},formContainer:{backgroundColor:'#fff',borderRadius:16,padding:20,marginBottom:20,elevation:3,shadowColor:'#000',shadowOffset:{width:0,height:2},shadowOpacity:0.1,shadowRadius:4},inputGroup:{marginBottom:20},label:{fontSize:16,fontWeight:'600',color:'#34495e',marginBottom:8},input:{borderWidth:1,borderColor:'#ddd',borderRadius:12,padding:14,fontSize:16,backgroundColor:'#fafafa'},textArea:{height:80,textAlignVertical:'top'},buttonRow:{flexDirection:'row',justifyContent:'space-between'},button:{flexDirection:'row',alignItems:'center',justifyContent:'center',paddingVertical:14,paddingHorizontal:20,borderRadius:12,flex:1,marginHorizontal:5},saveButton:{backgroundColor:'#4285F4'},editButton:{backgroundColor:'#34A853'},buttonIcon:{width:20,height:20,marginRight:8},buttonText:{color:'#fff',fontSize:16,fontWeight:'600'},dataContainer:{backgroundColor:'#fff',borderRadius:16,padding:20,elevation:3,shadowColor:'#000',shadowOffset:{width:0,height:2},shadowOpacity:0.1,shadowRadius:4},dataHeader:{flexDirection:'row',justifyContent:'space-between',alignItems:'center',marginBottom:15},dataTitle:{fontSize:20,fontWeight:'bold',color:'#2c3e50'},clearButton:{flexDirection:'row',alignItems:'center'},clearIcon:{width:18,height:18,marginRight:5},clearText:{color:'#999',fontSize:14},emptyContainer:{paddingVertical:40,alignItems:'center'},emptyText:{color:'#999',fontSize:16},dataList:{marginTop:10},dataItem:{flexDirection:'row',alignItems:'center',paddingVertical:15,borderBottomWidth:1,borderBottomColor:'#eee'},dataContent:{flex:1,paddingRight:10},itemKey:{fontSize:16,fontWeight:'600',color:'#34495e',marginBottom:5},itemValue:{fontSize:14,color:'#7f8c8d',lineHeight:20},deleteButton:{padding:10},deleteIcon:{width:22,height:22}});exportdefaultApp;这段React Native代码实现了一个本地数据存储管理系统的用户界面和交互逻辑,其核心原理基于React的状态管理和React Native的原生组件系统。从鸿蒙系统适配的角度深入分析,该代码体现了现代跨平台移动应用开发的核心理念。
代码通过useState钩子管理三个核心状态:key(键名)、value(值)和items(存储的键值对集合)。这种状态管理模式与鸿蒙系统的分布式数据管理理念高度契合,鸿蒙系统强调数据驱动的UI更新机制,而React的单向数据流正好满足这一需求。当用户在输入框中输入数据时,通过onChangeText回调函数实时更新组件状态,触发界面重新渲染,这种响应式更新机制在鸿蒙设备上能够提供流畅的用户体验。
saveData函数实现了数据的存储逻辑,通过展开运算符创建新的items对象,避免直接修改原状态,这符合React不可变数据的原则。在鸿蒙系统中,这种数据处理方式能够更好地适配其分布式数据管理机制,确保数据状态的一致性和可预测性。函数中包含的数据验证逻辑体现了良好的用户体验设计,通过Alert组件提供即时反馈,这种交互模式在鸿蒙系统的原生应用中也广泛使用。
deleteItem函数采用delete操作符从items对象中移除指定键值对,通过创建新对象的方式保持状态的不可变性。这种实现方式在鸿蒙系统的内存管理中具有优势,能够有效避免内存泄漏问题。clearAll函数通过设置空对象实现数据清空,体现了简洁高效的设计思想。
loadItem函数实现了编辑模式下的数据加载功能,当用户点击已存储的数据项时,将选中项的键值填充到输入框中。这种交互模式在鸿蒙系统的应用设计中很常见,体现了直观易用的用户界面设计理念。
UI布局采用ScrollView作为根容器,确保内容在小屏幕设备上的可滚动性,这在鸿蒙系统的多设备适配中至关重要。View组件作为布局容器,通过flex布局实现响应式设计,能够自适应不同尺寸的鸿蒙设备屏幕。
TextInput组件实现了用户输入功能,通过multiline属性支持多行文本输入,numberOfLines属性控制显示行数。在鸿蒙系统中,这种输入组件会自动适配系统的输入法和键盘布局,提供原生的输入体验。TouchableOpacity组件实现触摸交互,其内置的触摸反馈效果符合鸿蒙系统的交互设计规范。
样式系统采用StyleSheet.create方式定义,这种做法在鸿蒙环境中能够获得更好的性能表现。通过样式对象的组合应用,实现复杂的视觉效果。背景色#f5f8fa等设计细节体现了现代化的UI设计理念,与鸿蒙系统的设计语言保持一致。
数据展示区域通过Object.entries方法将键值对转换为数组进行遍历渲染,每个数据项包含内容展示区和删除按钮。这种列表渲染模式在鸿蒙应用中广泛使用,能够高效处理动态数据集合。
整体而言,该代码通过React Native的跨平台能力,充分利用了鸿蒙系统的原生特性,在保持代码一致性的同时,为用户提供接近原生应用的使用体验。代码结构清晰,状态管理合理,交互逻辑完善,体现了现代移动应用开发的最佳实践。
打包
接下来通过打包命令npn run harmony将reactNative的代码打包成为bundle,这样可以进行在开源鸿蒙OpenHarmony中进行使用。
打包之后再将打包后的鸿蒙OpenHarmony文件拷贝到鸿蒙的DevEco-Studio工程目录去:
最后运行效果图如下显示: