1.数据持久化
数据持久化是移动端的一个重要部分,刚发现 Realm 原来已经支持 React-Native 了
步骤一: 引入 realm
$ npm install realm --save
步骤二: 添加 Realm 与 工程的链接
react-native >= 0.31.0
react-native link realm
react-native < 0.31.0
rnpm link realm
首先,在为了方便使用,也为了减少第三方框架对工程的 “污染”,我们需要对框架进行一次 基础 的封装。
realmStorage.js
/** * 数据持久化 * 本地数据存储 */// 提供变量,便于外部调用var RealmBase = {};import Realm from 'realm';// 创建数据表(首页)const HomeSchame = { name:'HomeData', properties:{ id:'int', title:'string', image:'string', mall:'string', // 商城平台 pubtime:'string', fromsite:'string', }};// 创建数据表(海淘)const HTSchame = { name:'HTData', properties:{ id:'int', title:'string', image:'string', mall:'string', pubtime:'string', fromsite:'string', }};// 初始化realmlet realm = new Realm({schema:[HomeSchame, HTSchame]});// 增加RealmBase.create = function (schame, data) { realm.write(() => { for (let i = 0; i{ // 获取对象 let objects = realm.objects(schame); // 删除表 realm.delete(objects); })}global.RealmBase = RealmBase;
GDMain.js 调用
// 引入 HTTP封装组件import HTTP from '../http/HTTPBase';// 引入 本地数据存储封装组件 (数据持久化)import RealmStorage from '../storage/realmStorage';
GDHome.js
/** * 首页 */import React, { Component } from 'react';import { StyleSheet, Text, View, TouchableOpacity, Image, ListView, Dimensions, ActivityIndicator, Modal, // 模态 AsyncStorage, // 缓存数据库(数据持久化)} from 'react-native';// 引入 下拉刷新组件import {PullList} from 'react-native-pull';// 导航器import CustomerComponents, { Navigator} from 'react-native-deprecated-custom-components';// 获取屏幕宽高const {width, height} = Dimensions.get('window');// 引入自定义导航栏组件import CommunalNavBar from '../main/GDCommunalNavBar';// 引入 近半小时热门组件import HalfHourHot from './GDHalfHourHot';// 引入 搜索页面组件import Search from '../main/GDSearch';// 引入 cellimport CommunalHotCell from '../main/GDCommunalHotCell';// 引入 详情页 组件import CommunalDetail from '../main/GDCommunalDetail';// 引入 空白页组件import NoDataView from '../main/GDNoDataView';export default class GDHome extends Component { // 构造 constructor(props) { super(props); // 初始状态 this.state = { dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}), // 数据源 优化 loaded: false, // 用于判断是否显示空白页 isModal: false, // 用于判断模态的可见性 }; // 全局定义一个空数组用于存储列表数据 this.data = []; // 绑定 this.loadData = this.loadData.bind(this); this.loadMore = this.loadMore.bind(this); } // 加载最新数据网络请求 loadData(resolve) { let params = {"count" : 10 }; HTTPBase.get('https://guangdiu.com/api/getlist.php', params) .then((responseData) => { // 情况数组(刷新时) this.data = []; // 拼接数据 this.data = this.data.concat(responseData.data); // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); // 关闭刷新动画 if (resolve !== undefined){ setTimeout(() => { resolve(); }, 1000); } // 存储数组中最后一个元素的id let cnlastID = responseData.data[responseData.data.length - 1].id; AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 只能存储字符或字符串 // 首页存储数组中第一个元素的id let cnfirstID = responseData.data[0].id; AsyncStorage.setItem('cnfirstID', cnfirstID.toString()); // 清除本地存储的数据 RealmBase.removeAllData('HomeData'); // 存储数据到本地 RealmBase.create('HomeData', responseData.data); // 向数据表存储数据 }) .catch((error) => { // 数据加载失败,拿到本地存储的数据,展示出来,如果没有存储,那就显示无数据页面 this.data = RealmBase.loadAll('HomeData'); // 从数据表提取数据 // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); }) } // 加载更多数据的网络请求 loadMoreData(value) { let params = { "count" : 10, "sinceid" : value }; HTTPBase.get('https://guangdiu.com/api/getlist.php', params) .then((responseData) => { // 拼接数据 this.data = this.data.concat(responseData.data); // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); // 存储数组中最后一个元素的id let cnlastID = responseData.data[responseData.data.length - 1].id; AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 只能存储字符或字符串 }) .catch((error) => { }) } // 加载更多数据操作 loadMore() { // 读取存储的id AsyncStorage.getItem('cnlastID') .then((value) => { // 数据加载操作 this.loadMoreData(value); }) } // 模态到近半小时热门 pushToHalfHourHot() { this.setState({ isModal: true }) } // 跳转到搜索页面 pushToSearch() { this.props.navigator.push({ component: Search, }) } // 安卓模态销毁模态 onRequestClose() { this.setState({ isModal: false }) } // 关闭模态 closeModal(data) { this.setState({ isModal:data }) } // 返回左边按钮 renderLeftItem() { // 将组件返回出去 return({this.pushToHalfHourHot()}} > ); } // 返回中间按钮 renderTitleItem() { return(); } // 返回右边按钮 renderRightItem() { return( {this.pushToSearch()}} > ); } // ListView尾部 renderFooter() { return (); } // 根据网络状态决定是否渲染 listView renderListView() { if(this.state.loaded === false) { // 显示空白页 return( ); }else{ return( this.loadData(resolve)} // 数据源 通过判断dataSource是否有变化,来判断是否要重新渲染 dataSource={this.state.dataSource} renderRow={this.renderRow.bind(this)} // 隐藏水平线 showsHorizontalScrollIndicator={false} style={styles.listViewStyle} initialListSize={5} // 返回 listView 头部 renderHeader={this.renderHeader} // 上拉加载更多 onEndReached={this.loadMore} onEndReachedThreshold={60} renderFooter={this.renderFooter} /> ); } } // 通过id 跳转详情页 pushToDetail(value) { this.props.navigator.push({ component:CommunalDetail, params: { url: 'https://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value } }) } // 返回每一行cell的样式 renderRow(rowData) { // 使用cell组件 return( this.pushToDetail(rowData.id)} > ); } // 生命周期 组件渲染完成 已经出现在dom文档里 componentDidMount() { // 请求数据 this.loadData(); } render() { return ({/* 初始化模态 */} ); }}const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', }, navbarLeftItemStyle: { width:20, height:20, marginLeft:15, }, navbarTitleItemStyle: { width:66, height:20, }, navbarRightItemStyle: { width:20, height:20, marginRight:15, }, listViewStyle: { width:width, },});this.onRequestClose()} // 销毁 > {/* 导航栏样式 */}{ let Component = route.component; return this.closeModal(data)} {...route.params} navigator={navigator} /> }} /> this.renderLeftItem()} titleItem = {() => this.renderTitleItem()} rightItem = {() => this.renderRightItem()} /> {/* 根据网络状态决定是否渲染 listView */} {this.renderListView()}
核心代码:
// 加载最新数据网络请求 loadData(resolve) { let params = {"count" : 10 }; HTTPBase.get('https://guangdiu.com/api/getlist.php', params) .then((responseData) => { // 情况数组(刷新时) this.data = []; // 拼接数据 this.data = this.data.concat(responseData.data); // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); // 关闭刷新动画 if (resolve !== undefined){ setTimeout(() => { resolve(); }, 1000); } // 存储数组中最后一个元素的id let cnlastID = responseData.data[responseData.data.length - 1].id; AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 只能存储字符或字符串 // 首页存储数组中第一个元素的id let cnfirstID = responseData.data[0].id; AsyncStorage.setItem('cnfirstID', cnfirstID.toString()); // 清除本地存储的数据 RealmBase.removeAllData('HomeData'); // 存储数据到本地 RealmBase.create('HomeData', responseData.data); // 向数据表存储数据 }) .catch((error) => { // 数据加载失败,拿到本地存储的数据,展示出来,如果没有存储,那就显示无数据页面 this.data = RealmBase.loadAll('HomeData'); // 从数据表提取数据 // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); }) }
2.因为 realm 下载的内容过大,不易上传至 github 需要在 .gitignore 上设置 忽略
/node_modules/realm/*
3.设置 ListView 默认显示条数,避免列表下出现空白
4.自定义详情cell
首先,还是一样,我们先来创建 GDCommunalCell 文件,并且我们将前面 自定义cell 里面的内容 copy 一下,放到这个文件中,并进行相应修改:
GDCommunalCell.js
/** * 公共 Cell */import React, { Component, PropTypes } from 'react';import { StyleSheet, Text, View, Dimensions, Platform, Image,} from 'react-native';// 获取屏幕宽高const {width, height} = Dimensions.get('window');export default class GDCommunalCell extends Component { // 定义成员属性 static propTypes = { image:PropTypes.string, title:PropTypes.string, mall:PropTypes.string, // 平台 pubTime:PropTypes.string, // 时间 fromSite:PropTypes.string, // 来源 }; renderDate(pubTime, fromSite) { // 时间差的计算 let minute = 1000 * 60; // 1分钟 let hour = minute * 60; // 1小时 let day = hour * 24; // 1天 let week = day * 7; // 1周 let month = day * 30; // 1个月 // 计算时间差 let now = new Date().getTime(); // 获取当前时间 let diffValue = now - Date.parse(pubTime.replace(/-/gi, "/")); if (diffValue < 0) return; let monthC = diffValue/month; // 相差了几个月 let weekC = diffValue/week; // 相差几周 let dayC = diffValue/day; // 相差几天 let hourC = diffValue/hour // 相差几小时 let minuteC = diffValue/minute; // 相差几分钟 let result; if (monthC >= 1) { result = parseInt(monthC) + "月前"; }else if (weekC >= 1) { result = parseInt(weekC) + "周前"; }else if (dayC >= 1) { result = parseInt(dayC) + "天前"; }else if (hourC >= 1) { result = parseInt(hourC) + "小时前"; }else if (minuteC >= 1) { result = parseInt(minuteC) + "分钟前"; }else result = "刚刚"; return result + ' · ' + fromSite; } render() { return ({/* 左边图片 */} {/* 中间 */} ); }}const styles = StyleSheet.create({ container: { flexDirection:'row', alignItems:'center', justifyContent:'space-between', backgroundColor:'white', height:100, width:width, borderBottomWidth:0.5, borderBottomColor:'gray', marginLeft:15 }, imageStyle: { width:70, height:70, }, centerViewStyle: { height:70, justifyContent:'space-around', }, titleStyle: { width:width * 0.65, }, detailViewStyle: { flexDirection:'row', justifyContent:'space-between', alignItems:'center' }, detailMallStyle: { fontSize:12, color:'green', }, timeStyle: { fontSize:12, color:'gray', }, arrowStyle: { width:10, height:10, marginRight:30, }});{/* 标题 */} {/* 右边的箭头 */}{/* 详情 */} {this.props.title} {/* 平台 */} {this.props.mall} {/* 时间 + 来源 */}{this.renderDate(this.props.pubTime, this.props.fromSite)}
GDHome.js 及 GDHt.js 调用
// 引入 公共cellimport CommunalCell from '../main/GDCommunalCell';
GDHome.js
/** * 首页 */import React, { Component } from 'react';import { StyleSheet, Text, View, TouchableOpacity, Image, ListView, Dimensions, ActivityIndicator, Modal, // 模态 AsyncStorage, // 缓存数据库(数据持久化)} from 'react-native';// 引入 下拉刷新组件import {PullList} from 'react-native-pull';// 导航器import CustomerComponents, { Navigator} from 'react-native-deprecated-custom-components';// 获取屏幕宽高const {width, height} = Dimensions.get('window');// 引入自定义导航栏组件import CommunalNavBar from '../main/GDCommunalNavBar';// 引入 近半小时热门组件import HalfHourHot from './GDHalfHourHot';// 引入 搜索页面组件import Search from '../main/GDSearch';// 引入 公共cellimport CommunalCell from '../main/GDCommunalCell';// 引入 详情页 组件import CommunalDetail from '../main/GDCommunalDetail';// 引入 空白页组件import NoDataView from '../main/GDNoDataView';export default class GDHome extends Component { // 构造 constructor(props) { super(props); // 初始状态 this.state = { dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}), // 数据源 优化 loaded: false, // 用于判断是否显示空白页 isModal: false, // 用于判断模态的可见性 }; // 全局定义一个空数组用于存储列表数据 this.data = []; // 绑定 this.loadData = this.loadData.bind(this); this.loadMore = this.loadMore.bind(this); } // 加载最新数据网络请求 loadData(resolve) { let params = {"count" : 10 }; HTTPBase.get('https://guangdiu.com/api/getlist.php', params) .then((responseData) => { // 情况数组(刷新时) this.data = []; // 拼接数据 this.data = this.data.concat(responseData.data); // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); // 关闭刷新动画 if (resolve !== undefined){ setTimeout(() => { resolve(); }, 1000); } // 存储数组中最后一个元素的id let cnlastID = responseData.data[responseData.data.length - 1].id; AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 只能存储字符或字符串 // 首页存储数组中第一个元素的id let cnfirstID = responseData.data[0].id; AsyncStorage.setItem('cnfirstID', cnfirstID.toString()); // // 清除本地存储的数据 // RealmBase.removeAllData('HomeData'); // // 存储数据到本地 // RealmBase.create('HomeData', responseData.data); // 向数据表存储数据 }) .catch((error) => { // // 数据加载失败,拿到本地存储的数据,展示出来,如果没有存储,那就显示无数据页面 // this.data = RealmBase.loadAll('HomeData'); // 从数据表提取数据 // // 重新渲染 // this.setState({ // dataSource: this.state.dataSource.cloneWithRows(this.data), // loaded:true, // }); }) } // 加载更多数据的网络请求 loadMoreData(value) { let params = { "count" : 10, "sinceid" : value }; HTTPBase.get('https://guangdiu.com/api/getlist.php', params) .then((responseData) => { // 拼接数据 this.data = this.data.concat(responseData.data); // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); // 存储数组中最后一个元素的id let cnlastID = responseData.data[responseData.data.length - 1].id; AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 只能存储字符或字符串 }) .catch((error) => { }) } // 加载更多数据操作 loadMore() { // 读取存储的id AsyncStorage.getItem('cnlastID') .then((value) => { // 数据加载操作 this.loadMoreData(value); }) } // 模态到近半小时热门 pushToHalfHourHot() { this.setState({ isModal: true }) } // 跳转到搜索页面 pushToSearch() { this.props.navigator.push({ component: Search, }) } // 安卓模态销毁模态 onRequestClose() { this.setState({ isModal: false }) } // 关闭模态 closeModal(data) { this.setState({ isModal:data }) } // 返回左边按钮 renderLeftItem() { // 将组件返回出去 return({this.pushToHalfHourHot()}} > ); } // 返回中间按钮 renderTitleItem() { return(); } // 返回右边按钮 renderRightItem() { return( {this.pushToSearch()}} > ); } // ListView尾部 renderFooter() { return (); } // 根据网络状态决定是否渲染 listView renderListView() { if(this.state.loaded === false) { // 显示空白页 return( ); }else{ return( this.loadData(resolve)} // 数据源 通过判断dataSource是否有变化,来判断是否要重新渲染 dataSource={this.state.dataSource} renderRow={this.renderRow.bind(this)} // 隐藏水平线 showsHorizontalScrollIndicator={false} style={styles.listViewStyle} initialListSize={7} // 默认渲染数据条数 // 返回 listView 头部 renderHeader={this.renderHeader} // 上拉加载更多 onEndReached={this.loadMore} onEndReachedThreshold={60} renderFooter={this.renderFooter} /> ); } } // 通过id 跳转详情页 pushToDetail(value) { this.props.navigator.push({ component:CommunalDetail, params: { url: 'https://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value } }) } // 返回每一行cell的样式 renderRow(rowData) { // 使用cell组件 return( this.pushToDetail(rowData.id)} > ); } // 生命周期 组件渲染完成 已经出现在dom文档里 componentDidMount() { // 请求数据 this.loadData(); } render() { return ({/* 初始化模态 */} ); }}const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', }, navbarLeftItemStyle: { width:20, height:20, marginLeft:15, }, navbarTitleItemStyle: { width:66, height:20, }, navbarRightItemStyle: { width:20, height:20, marginRight:15, }, listViewStyle: { width:width, },});this.onRequestClose()} // 销毁 > {/* 导航栏样式 */}{ let Component = route.component; return this.closeModal(data)} {...route.params} navigator={navigator} /> }} /> this.renderLeftItem()} titleItem = {() => this.renderTitleItem()} rightItem = {() => this.renderRightItem()} /> {/* 根据网络状态决定是否渲染 listView */} {this.renderListView()}
GDHt.js
/** * 海淘折扣 */import React, { Component } from 'react';import { StyleSheet, Text, View, TouchableOpacity, Image, ListView, Dimensions, ActivityIndicator, Modal, // 模态 AsyncStorage, // 缓存数据库(数据持久化)} from 'react-native';// 引入 下拉刷新组件import {PullList} from 'react-native-pull';// 导航器import CustomerComponents, { Navigator} from 'react-native-deprecated-custom-components';// 获取屏幕宽高const {width, height} = Dimensions.get('window');// 引入自定义导航栏组件import CommunalNavBar from '../main/GDCommunalNavBar';// 引入 近半小时热门组件import USHalfHourHot from './GDUSHalfHourHot';// 引入 搜索页面组件import Search from '../main/GDSearch';// 引入 cellimport CommunalCell from '../main/GDCommunalCell';// 引入 详情页 组件import CommunalDetail from '../main/GDCommunalDetail';// 引入 空白页组件import NoDataView from '../main/GDNoDataView';export default class GDHome extends Component { // 构造 constructor(props) { super(props); // 初始状态 this.state = { dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}), // 数据源 优化 loaded: false, // 用于判断是否显示空白页 isModal: false, // 用于判断模态的可见性 }; // 全局定义一个空数组用于存储列表数据 this.data = []; // 绑定 this.loadData = this.loadData.bind(this); this.loadMore = this.loadMore.bind(this); } // 加载最新数据网络请求 loadData(resolve) { let params = { "count" : 10, "country" : "us" }; HTTPBase.get('https://guangdiu.com/api/getlist.php', params) .then((responseData) => { // 清空数组(刷新时) this.data = []; // 拼接数据 this.data = this.data.concat(responseData.data); // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); // 关闭刷新动画 if (resolve !== undefined){ setTimeout(() => { resolve(); }, 1000); } // 存储数组中最后一个元素的id let uslastID = responseData.data[responseData.data.length - 1].id; AsyncStorage.setItem('uslastID', uslastID.toString()); // 只能存储字符或字符串 // 首页存储数组中第一个元素的id let usfirstID = responseData.data[0].id; AsyncStorage.setItem('usfirstID', usfirstID.toString()); // // 清除本地存储的数据 // RealmBase.removeAllData('HomeData'); // // 存储数据到本地 // RealmBase.create('HomeData', responseData.data); // 向数据表存储数据 }) .catch((error) => { // // 数据加载失败,拿到本地存储的数据,展示出来,如果没有存储,那就显示无数据页面 // this.data = RealmBase.loadAll('HomeData'); // 从数据表提取数据 // // 重新渲染 // this.setState({ // dataSource: this.state.dataSource.cloneWithRows(this.data), // loaded:true, // }); }) } // 加载更多数据的网络请求 loadMoreData(value) { let params = { "count" : 10, "country" : "us", "sinceid" : value }; HTTPBase.get('https://guangdiu.com/api/getlist.php', params) .then((responseData) => { // 拼接数据 this.data = this.data.concat(responseData.data); // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); // 存储数组中最后一个元素的id let uslastID = responseData.data[responseData.data.length - 1].id; AsyncStorage.setItem('uslastID', uslastID.toString()); // 只能存储字符或字符串 }) .catch((error) => { }) } // 加载更多数据操作 loadMore() { // 读取存储的id AsyncStorage.getItem('uslastID') .then((value) => { // 数据加载操作 this.loadMoreData(value); }) } // 模态到近半小时热门 pushToHalfHourHot() { this.setState({ isModal: true }) } // 跳转到搜索页面 pushToSearch() { this.props.navigator.push({ component: Search, }) } // 安卓模态销毁模态 onRequestClose() { this.setState({ isModal: false }) } // 关闭模态 closeModal(data) { this.setState({ isModal:data }) } // 返回左边按钮 renderLeftItem() { // 将组件返回出去 return({this.pushToHalfHourHot()}} > ); } // 返回中间按钮 renderTitleItem() { return(); } // 返回右边按钮 renderRightItem() { return( {this.pushToSearch()}} > ); } // ListView尾部 renderFooter() { return (); } // 根据网络状态决定是否渲染 listView renderListView() { if(this.state.loaded === false) { // 显示空白页 return( ); }else{ return( this.loadData(resolve)} // 数据源 通过判断dataSource是否有变化,来判断是否要重新渲染 dataSource={this.state.dataSource} renderRow={this.renderRow.bind(this)} // 隐藏水平线 showsHorizontalScrollIndicator={false} style={styles.listViewStyle} initialListSize={7} // 返回 listView 头部 renderHeader={this.renderHeader} // 上拉加载更多 onEndReached={this.loadMore} onEndReachedThreshold={60} renderFooter={this.renderFooter} /> ); } } // 通过id 跳转详情页 pushToDetail(value) { this.props.navigator.push({ component:CommunalDetail, params: { url: 'https://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value } }) } // 返回每一行cell的样式 renderRow(rowData) { // 使用cell组件 return( this.pushToDetail(rowData.id)} > ); } // 生命周期 组件渲染完成 已经出现在dom文档里 componentDidMount() { // 请求数据 this.loadData(); } render() { return ({/* 初始化模态 */} ); }}const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', }, navbarLeftItemStyle: { width:20, height:20, marginLeft:15, }, navbarTitleItemStyle: { width:66, height:20, }, navbarRightItemStyle: { width:20, height:20, marginRight:15, }, listViewStyle: { width:width, },});this.onRequestClose()} // 销毁 > {/* 导航栏样式 */}{ let Component = route.component; return this.closeModal(data)} {...route.params} navigator={navigator} /> }} /> this.renderLeftItem()} titleItem = {() => this.renderTitleItem()} rightItem = {() => this.renderRightItem()} /> {/* 根据网络状态决定是否渲染 listView */} {this.renderListView()}
.