本文共 15519 字,大约阅读时间需要 51 分钟。
本文出自系列文章。
每天一个知识点(技巧,经验,填坑日记等),每天学一点,离大神近一点。汇聚知识,分享精华。
如果你是一名React Native爱好者,或者有一颗热爱钻研新技术的心,喜欢分享技术干货、项目经验、以及你在React Naive学习研究或实践中的一些经验心得等等,欢迎投稿《React Native 每日一学》栏目。
如果你是一名Android、iOS、或前端开发人员,有者一颗积极进取的心,欢迎关注《React Native 每日一学》。本栏目汇聚React Native开发的技巧,知识点,经验等。
模板: D1:标题 (日期)------概述### 子标题内容 ### 子标题内容 另外:记得在列表中添加链接
AsyncStorage是React Native推荐的数据存储方式。当我们需要根据条件从本地查询出多条记录时,你会想到来一个select * from xx where xx
。但是很不幸的告诉你,AsyncStorage
那么如何才能快速的从众多记录中将符合条件的记录查询出来呢?
请往下看…为了方便查询多条符合规则的记录,我们可以在保存数据前,对这条数据进行分类,然后记录下这条记录的key。下次再查询该数据前,只需要先查询之前保存的key,然后通过
static multiGet(keys, callback?)
API,将符合规则的数据一并查询出来。 保存数据
第一步:保存数据
saveFavoriteItem(key,vaule,callback) { AsyncStorage.setItem(key,vaule,(error,result)=>{ if (!error) { //更新Favorite的key this.updateFavoriteKeys(key,true); } }); }
第二步:更新key
/** * 更新Favorite key集合 * @param isAdd true 添加,false 删除 * **/ updateFavoriteKeys(key,isAdd){ AsyncStorage.getItem(this.favoriteKey,(error,result)=>{ if (!error) { var favoriteKeys=[]; if (result) { favoriteKeys=JSON.parse(result); } var index=favoriteKeys.indexOf(key); if(isAdd){ if (index===-1)favoriteKeys.push(key); }else { if (index!==-1)favoriteKeys.splice(index, 1); } AsyncStorage.setItem(this.favoriteKey,JSON.stringify(favoriteKeys)); } }); }
查询批量数据
第一步:查询key
getFavoriteKeys(){ //获取收藏的Respository对应的key return new Promise((resolve,reject)=>{ AsyncStorage.getItem(this.favoriteKey,(error,result)=>{ if (!error) { try { resolve(JSON.parse(result)); } catch (e) { reject(error); } }else { reject(error); } }); }); }
第二步:根据key查询数据
AsyncStorage.multiGet(keys, (err, stores) => { try { stores.map((result, i, store) => { // get at each store's key/value so you can work with it let key = store[i][0]; let value = store[i][1]; if (value)items.push(JSON.parse(value)); }); resolve(items); } catch (e) { reject(e); } }); ```>**以上是我在使用AsyncStorage进行批量数据查询的一些思路,大家根据实际情况进行调整。** D10:优化切换动画卡顿的问题(2016-8-31)------使用API InteractionManager,它的作用就是可以使本来JS的一些操作在动画完成之后执行,这样就可确保动画的流程性。当然这是在延迟执行为代价上来获得帧数的提高。```javascript InteractionManager.runAfterInteractions(()=>{ //...耗时较长的同步任务... //更新state也需要时间 this.setState({ ... }) //获取某些数据,需要长时间等待 this.fetchData(arguements) })
在 ES6+ 中,我们不仅可以在对象字面量属性的定义中使用表达式,还有使用使用字符串模板:
class Form extends React.Component { onChange(inputName, e) { this.setState({ [`${inputName}Value`]: e.target.value, }); }}
在项目中遇到地图,拨打电话,清除缓存等iOS与Andiorid机制不同的功能,就需要调用原生的界面或模块,这里说下React Native调用iOS原生模块,Andiorid也是大同小异
#import#import "RCTBridgeModule.h"@interface KSDMapManager : NSObject @end
@implementation KSDMapManager//导出模块RCT_EXPORT_MODULE();RCT_EXPORT_METHOD(gotoIM:(RCTResponseSenderBlock)callback){ __weak typeof(self) weakSelf = self; self.callback = callback; UIViewController *controller = (UIViewController*)[[[UIApplication sharedApplication] keyWindow] rootViewController]; KSDMapLocationViewController *mapVc = [[KSDMapLocationViewController alloc] init]; mapVc.handle = ^(NSString *address) { weakSelf.itemValue = address; NSArray *events = [[NSArray alloc] initWithObjects:self.itemValue, nil]; callback(events); }; [controller presentViewController:mapVc animated:YES completion:nil];}
//创建原生模块实例var KSDMapManager = NativeModules.KSDMapManager;//方法调用KSDMapManager.gotoIM( (events)=>{ this._inputReceiveAddress(events); console.log(events); })
解构赋值语法是JavaScript的一种表达式,可以方便的从数组或者对象中快速提取值赋给定义的变量。
从数组中获取值并赋值到变量中,变量的顺序与数组中对象顺序对应。
var foo = ["one", "two", "three", "four"];var [one, two, three] = foo;console.log(one); // "one"console.log(two); // "two"console.log(three); // "three"//如果你要忽略某些值,你可以按照下面的写法获取你想要的值var [first, , , last] = foo;console.log(first); // "one"console.log(last); // "four"//你也可以这样写var a, b; //先声明变量[a, b] = [1, 2];console.log(a); // 1console.log(b); // 2
如果没有从数组中的获取到值,你可以为变量设置一个默认值。
var a, b;[a=5, b=7] = [1];console.log(a); // 1console.log(b); // 7
通过解构赋值可以方便的交换两个变量的值。
var a = 1;var b = 3;[a, b] = [b, a];console.log(a); // 3console.log(b); // 1
从对象中获取对象属性的值,在声明变量的时候要与对象的属性名保持一致。
var o = {p: 42, q: true};var {p, q} = o;console.log(p); // 42console.log(q); // true//你也可以这样写var a, b;({a, b} = {a:1, b:2});console.log(a); // 1console.log(b); // 2
可以从一个对象中获取对象属性的值并赋值给与对象属性名不同的变量。
var o = {p: 42, q: true};var {p: foo, q: bar} = o;console.log(foo); // 42 console.log(bar); // true
和获取数组中的值一样,从对象中获取属性的值也可以设置一个默认值。
var {a=10, b=5} = {a: 3};console.log(a); // 3console.log(b); // 5
ref属性不仅接受string类型的参数,而且它还接受一个function作为callback。这一特性让开发者对ref的使用更加灵活。
render: function() { return (); },
在ES6中我们可以使用箭头函数来为组件的ref设置一个callback。
render() { returnthis._input = c} />; }, componentDidMount() { this._input.focus(); },
需要提醒大家的是,只有在组件的render方法被调用时,ref才会被调用,组件才会返回ref。如果你在调用this.refs.xx时render方法还没被调用,那么你得到的是undefined。
心得:ref属性在开发中使用频率很高,使用它你可以获取到任何你想要获取的组件的对象,有个这个对象你就可以灵活地做很多事情,比如:读写对象的变量,甚至调用对象的函数。
有时候我们需要直接改动组件并触发局部的刷新,但不使用state
或是props
。
setNativeProps
方法可以理解为web的直接修改dom。使用该方法修改 View
、 Text
等 RN自带的组件 ,则不会触发组件的 componentWillReceiveProps
、 shouldComponentUpdate
、componentWillUpdate
等组件生命周期中的方法。 javascript class MyButton extends React.Component({ setNativeProps(nativeProps) { this._root.setNativeProps({ //这里输入你要修改的组件style height:48, backgroundColor:'red' }); }, render() { return ( <View ref={component => this._root = component} {...this.props} style={styles.button}> <Text>{this.props.label}</Text> </View> ) }, });
render
方法的冲突如果要更新一个由render
方法来维护的属性,则可能会碰到一些出人意料的bug。因为每一次组件重新渲染都可能引起属性变化,这样一来,之前通过setNativeProps
所设定的值就被完全忽略和覆盖掉了。
在ES6的class中函数不再被自动绑定,你需要手动去绑定它们。
第一种在构造函数里绑定。
constructor(props) { super(props); // Set up initial state this.state = { text: props.initialValue || 'placeholder' }; // Functions must be bound manually with ES6 classes this.handleChange = this.handleChange.bind(this);
另一种方式就是在你使用的地方通过内联来绑定:
// Use `.bind`: render() { return ( );}// Use an arrow function:render() { return ( this.handleChange()} value={this.state.text} />);
以上任意一种都可以,然而在效率上却不行了。每一次调用render(可以说是非常频繁!)一个新的函数都会被创建。与在构造函数里只绑定一次相比就慢一些。
最终的选择是使用箭头函数直接替换函数在类中的声明,像这样:
// the normal way// requires binding elsewherehandleChange(event) { this.setState({ text: event.target.value });}// the ES7 way// all done, no binding requiredhandleChange = (event) => { this.setState({text: event.target.value });}
通过这种方式,你不需要绑定任何东西。这都已经通过神奇的箭头函数被搞定了。像期望的那样,函数内部的this将会指向组件实例。
参考:开发中真机调试是必不可少的,有些功能和问题模拟器是无法重现的,所以就需要配合真机测试,接下来就说下安卓和iOS的真机调试,不难,但是有很多细节需要注意
必须
保证调试用电脑的和你的设备处于相同的 WiFi
网络环境中下在 Android 设备上打开 USB debugging 并连接上电脑启动调试。
在真机上运行的方法与在模拟器上运行一致,都是通过 react-native run-android 来安装并且运行你的 React Native 应用。
如果不是 Android 5.0+ (API 21) ,那么就没办法通过 adb reverse 进行调试,需要通过 WiFi 来连接上你的开发者服务器
注:因为本人不是安卓开发,所以参考
其实还是有些坑的,这里只说iOS 如开始所说,必须是同一网络下,有时电脑同时开着Wifi和插着网线,建议把网线拔掉,但是也不排除可以,没有试过,还有就是
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
这一句千万不能注释,需要注意的就这几点,很简单
开发中经常需要 import 其他 js 文件,如果需要同时导入一些相关的 js 文件时,可以创建一个索引文件方便引用。
在 index.js 中 import 相关的 js 文件
'use strict';import * as Type from './network/EnvironmentConst';import Request from './network/RequestManager';import AppContext from './network/AppContext';import ApiServiceFactory from './network/ApiServiceFactory';module.exports = { ApiServiceFactory, Type, Request, AppContext};
如果需要使用这些类,只需要导入index文件就可以了~
import {Request, ApiServiceFactory, AppContext, Type} from '../expand/index';
自 React Native 0.4.3,你可以以导入的形式,来读取本地的json文件,导入的文件可以作为一个js对象使用。
var langsData = require('../../../res/data/langs.json');
ES6/ES2015
import langsData from '../../../res/data/langs.json'
如果langs.json
的路径正确切没有格式错误,那么现在你可以操作langsData
对象了。
读取langs.json
使用langs.json
@
汇聚知识,分享精华。
如果你是一名React Native爱好者,或者有一颗热爱钻研新技术的心,喜欢分享技术干货、项目经验、以及你在React Naive学习研究或实践中的一些经验心得等等,欢迎投稿《React Native 每日一学》栏目。
如果你是一名Android、iOS、或前端开发人员,有者一颗积极进取的心,欢迎关注《React Native 每日一学》。本栏目汇聚React Native开发的技巧,知识点,经验等。
模板: D1:标题 (日期)------概述 ### 子标题内容 ### 子标题内容 另外:记得在列表中添加链接
在项目中遇到地图,拨打电话,清除缓存等iOS与Andiorid机制不同的功能,就需要调用原生的界面或模块,这里说下React Native调用iOS原生模块,Andiorid也是大同小异
#import#import "RCTBridgeModule.h"@interface KSDMapManager : NSObject @end
@implementation KSDMapManager//导出模块RCT_EXPORT_MODULE();RCT_EXPORT_METHOD(gotoIM:(RCTResponseSenderBlock)callback){ __weak typeof(self) weakSelf = self; self.callback = callback; UIViewController *controller = (UIViewController*)[[[UIApplication sharedApplication] keyWindow] rootViewController]; KSDMapLocationViewController *mapVc = [[KSDMapLocationViewController alloc] init]; mapVc.handle = ^(NSString *address) { weakSelf.itemValue = address; NSArray *events = [[NSArray alloc] initWithObjects:self.itemValue, nil]; callback(events); }; [controller presentViewController:mapVc animated:YES completion:nil];}
//创建原生模块实例var KSDMapManager = NativeModules.KSDMapManager;//方法调用KSDMapManager.gotoIM( (events)=>{ this._inputReceiveAddress(events); console.log(events); })
解构赋值语法是JavaScript的一种表达式,可以方便的从数组或者对象中快速提取值赋给定义的变量。
从数组中获取值并赋值到变量中,变量的顺序与数组中对象顺序对应。
var foo = ["one", "two", "three", "four"];var [one, two, three] = foo;console.log(one); // "one"console.log(two); // "two"console.log(three); // "three"//如果你要忽略某些值,你可以按照下面的写法获取你想要的值var [first, , , last] = foo;console.log(first); // "one"console.log(last); // "four"//你也可以这样写var a, b; //先声明变量[a, b] = [1, 2];console.log(a); // 1console.log(b); // 2
如果没有从数组中的获取到值,你可以为变量设置一个默认值。
var a, b;[a=5, b=7] = [1];console.log(a); // 1console.log(b); // 7
通过解构赋值可以方便的交换两个变量的值。
var a = 1;var b = 3;[a, b] = [b, a];console.log(a); // 3console.log(b); // 1
从对象中获取对象属性的值,在声明变量的时候要与对象的属性名保持一致。
var o = {p: 42, q: true};var {p, q} = o;console.log(p); // 42console.log(q); // true//你也可以这样写var a, b;({a, b} = {a:1, b:2});console.log(a); // 1console.log(b); // 2
可以从一个对象中获取对象属性的值并赋值给与对象属性名不同的变量。
var o = {p: 42, q: true};var {p: foo, q: bar} = o;console.log(foo); // 42 console.log(bar); // true
和获取数组中的值一样,从对象中获取属性的值也可以设置一个默认值。
var {a=10, b=5} = {a: 3};console.log(a); // 3console.log(b); // 5
ref属性不仅接受string类型的参数,而且它还接受一个function作为callback。这一特性让开发者对ref的使用更加灵活。
render: function() { return (); },
在ES6中我们可以使用箭头函数来为组件的ref设置一个callback。
render() { returnthis._input = c} />; }, componentDidMount() { this._input.focus(); },
需要提醒大家的是,只有在组件的render方法被调用时,ref才会被调用,组件才会返回ref。如果你在调用this.refs.xx时render方法还没被调用,那么你得到的是undefined。
心得:ref属性在开发中使用频率很高,使用它你可以获取到任何你想要获取的组件的对象,有个这个对象你就可以灵活地做很多事情,比如:读写对象的变量,甚至调用对象的函数。
有时候我们需要直接改动组件并触发局部的刷新,但不使用state
或是props
。
setNativeProps
方法可以理解为web的直接修改dom。使用该方法修改 View
、 Text
等 RN自带的组件 ,则不会触发组件的 componentWillReceiveProps
、 shouldComponentUpdate
、componentWillUpdate
等组件生命周期中的方法。 javascript class MyButton extends React.Component({ setNativeProps(nativeProps) { this._root.setNativeProps({ //这里输入你要修改的组件style height:48, backgroundColor:'red' }); }, render() { return ( <View ref={component => this._root = component} {...this.props} style={styles.button}> <Text>{this.props.label}</Text> </View> ) }, });
render
方法的冲突如果要更新一个由render
方法来维护的属性,则可能会碰到一些出人意料的bug。因为每一次组件重新渲染都可能引起属性变化,这样一来,之前通过setNativeProps
所设定的值就被完全忽略和覆盖掉了。
在ES6的class中函数不再被自动绑定,你需要手动去绑定它们。
第一种在构造函数里绑定。
constructor(props) { super(props); // Set up initial state this.state = { text: props.initialValue || 'placeholder' }; // Functions must be bound manually with ES6 classes this.handleChange = this.handleChange.bind(this);
另一种方式就是在你使用的地方通过内联来绑定:
// Use `.bind`: render() { return ( );}// Use an arrow function:render() { return ( this.handleChange()} value={this.state.text} />);
以上任意一种都可以,然而在效率上却不行了。每一次调用render(可以说是非常频繁!)一个新的函数都会被创建。与在构造函数里只绑定一次相比就慢一些。
最终的选择是使用箭头函数直接替换函数在类中的声明,像这样:
// the normal way// requires binding elsewherehandleChange(event) { this.setState({ text: event.target.value });}// the ES7 way// all done, no binding requiredhandleChange = (event) => { this.setState({text: event.target.value });}
通过这种方式,你不需要绑定任何东西。这都已经通过神奇的箭头函数被搞定了。像期望的那样,函数内部的this将会指向组件实例。
参考:开发中真机调试是必不可少的,有些功能和问题模拟器是无法重现的,所以就需要配合真机测试,接下来就说下安卓和iOS的真机调试,不难,但是有很多细节需要注意
必须
保证调试用电脑的和你的设备处于相同的 WiFi
网络环境中下在 Android 设备上打开 USB debugging 并连接上电脑启动调试。
在真机上运行的方法与在模拟器上运行一致,都是通过 react-native run-android 来安装并且运行你的 React Native 应用。
如果不是 Android 5.0+ (API 21) ,那么就没办法通过 adb reverse 进行调试,需要通过 WiFi 来连接上你的开发者服务器
注:因为本人不是安卓开发,所以参考
其实还是有些坑的,这里只说iOS 如开始所说,必须是同一网络下,有时电脑同时开着Wifi和插着网线,建议把网线拔掉,但是也不排除可以,没有试过,还有就是
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
这一句千万不能注释,需要注意的就这几点,很简单
开发中经常需要 import 其他 js 文件,如果需要同时导入一些相关的 js 文件时,可以创建一个索引文件方便引用。
在 index.js 中 import 相关的 js 文件
'use strict';import * as Type from './network/EnvironmentConst';import Request from './network/RequestManager';import AppContext from './network/AppContext';import ApiServiceFactory from './network/ApiServiceFactory';module.exports = { ApiServiceFactory, Type, Request, AppContext};
如果需要使用这些类,只需要导入index文件就可以了~
import {Request, ApiServiceFactory, AppContext, Type} from '../expand/index';
自 React Native 0.4.3,你可以以导入的形式,来读取本地的json文件,导入的文件可以作为一个js对象使用。
var langsData = require('../../../res/data/langs.json');
ES6/ES2015
import langsData from '../../../res/data/langs.json'
如果langs.json
的路径正确切没有格式错误,那么现在你可以操作langsData
对象了。
读取langs.json
使用langs.json
@
本文出自系列文章。
转载地址:http://jkevd.baihongyu.com/