React Native 技术分享markdown版本,请使用markdonw看该版本

# React Native

## 1.React Native之了解

### 1.1 Native开发优势:

>##### Native的原生控件有更好的体验;

>##### Native有更好的手势识别;

>##### Native有更合适的线程模型,尽管Web Worker可以解决一部分问题,但如图像解码、文本渲染仍无法多线程渲染,这影响了Web的流畅性。

### 1.2 React Native优势:

>#####1.既拥有Native的用户体验、又保留React的开发效率(RN通过JavaScript Core解析JavaScript模块,转换成原生Native组件渲染)

>##### 2.React Native基本完成了对多端的支持,可以灵活的使用HTML和CSS布局,使用React语法构建组件,实现:H5, Android, iOS多端代码的复用

>#####3.追求极致的用户体验:实时热部署(CodePush在修复一些小问题和添加新特性的时候,不需要经过二进制打包,可以直接推送代码进行实时更新。)

>##### 4.UI排版的问题:

######类似HTML + CSS的排版使用原生控件渲染的框架:

###### BeeFramework,BeeFramework虽然开源多年,而且有2000多的star数,但是受限于它自身的影响力以及框架的复杂性,一直没有很大的成功。

###### React Native采用了类似HTML + CSS的排版,可以内嵌到模块,也可以全局使用,定义样式变得非常简单通用。引入了Flexbox布局,使用很方便,学习起来也更简单。

>##### 5.动态绑定,这个React的基本功能,被带到了客户端开发中来,数据和视图是动态绑定的,数据发生变化,视图会跟着变化,很多操作视图的代码都可以省略了。

>##### 6.引入了方便的npm管理,有大量现成的nodejs包可以用(例如moment,underscore等常用模块),还可以把自己项目模块搞到内部npm上做通用组件,另外,npm上还有不少别人写的react native的插件。

>##### 7.第三方组件里有一个可以把icon font引入项目的组件,可以在任何显示图标的地方直接用icon font显示

>##### 8.调试很方便,一次编译后,每次改了js代码,只需要在模拟器里command+R即可重新加载代码。有问题会直接报错,里面有代码行数等详细信息。

>##### 9.完整封装了各种js内置的方法,例如:setTimeout,setInterval,XMLHttpRequest,localstorage,console.log等,都是用oc原生方法封装的。

>##### 10.引入ES6的支持,可以使用各种新特性,例如最常用的箭头函数,解决this作用域乱套的问题。

### 1.3 React Native是什么?

![基本概念](https://github.com/hebing789/markdown_img_hebin/raw/master/1.png)

>#####  Facebook于2015年9月15日发布React Native

>#####广大开发者可以使用JavaScript和React开发跨平台移动应用.

>##### React Native提倡组件化开发:即提供一个个封装好的组件,组件相互嵌套形成新的组件

### 1.4 React Native开发注意事项

>#####目前react native在iOS上仅支持iOS8以上,Android仅支持Android4.1以上版本;

>#####由于React Native的版本更新速度很快,如果没有深厚的JavaScript基础,建议选择:

######功能适中,交互一般,不需要特别多的系统原生支持;

######对于部分复杂的应用,可以考虑原生+React Native混合开发

>#####学习网站:

######  github地址:  https://github.com/facebook/react-native

######官网文档: http://facebook.github.io/react-native/docs/getting-started.html

### 1.5 React Native开发环境:

>#####参考中文React Native网站:

React Native开发环境配置


## 2.React Native之学习

### 2.1 FlexBox布局:

>#####弹性盒模型(The Flexible Box Module),又叫Flexbox,意为“弹性布局”,旨在通过弹性的方式来对齐和分布容器中内容的空间,使其能适应不同屏幕,为盒装模型提供最大的灵活性。

>##### Flex布局主要思想是:让容器有能力让其子项目能够改变其宽度、高度(甚至是顺序),以最佳方式填充可用空间;

>##### Flex学习入门网站:Flex布局教程

>##### flex基本概念:

![flex基本概念](http://www.ruanyifeng.com/blogimg/asset/2015/bg2015071004.png)

######采用Flex布局的元素,称为Flex容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为Flex项目(flex item),简称"项目"。

######容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。

######项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。

>##### **flex常用属性总结:**

>######容器属性:

###### flex-direction(主轴方向)

###### flex-wrap(是否换行)

###### justify-content(item在主轴对齐方式) ,

###### align-items(item在交叉轴上如何对齐) ,

>######元素属性:

###### Flex:弹性宽度:宽度=item该flex值/该容器所有item的flex和*(容器宽度-该容器item没有设置flex的直接宽度)

###### align-self:性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性

### 2.2 Touchable系列组件:

>#####***高亮触摸TouchableHighlight:***

当手指点击按下的时候,该视图的不透明度会进行降低同时会看到相应的颜色,其实现原理则是在底层新添加了一个View。TouchableHighlight只能进行一层嵌套,不能多层嵌套。

>######常用属性:

######activeOpacity  number设置组件在进行触摸的时候,显示的不透明度(取值在0-1之间)

######onHideUnderlay  function方法当底层被隐藏的时候调用

######onShowUnderlay  function方法当底层显示的时候调用

######style可以设置控件的风格演示,该风格演示可以参考View组件的style

###### underlayColor当触摸或者点击控件的时候显示出的颜色

>#####***不透明触摸TouchableOpacity***

该组件封装了响应触摸事件;当点击按下的时候,该组件的透明度会降低。等等

#####代码示例

```

style={styles.button}

source={require('./button.png')}

/>

```

```

style={styles.button}

source={require('image!myButton')}

/>

```

### 2.3组件生命周期:

![基本概念](https://github.com/hebing789/markdown_img_hebin/raw/master/2.png)

>#####***一:实例化阶段函数分析:***

######1,getDefaultProps

初始化一些默认的属性,通常会将固定的内容放在这个函数中进行初始化和赋值;

可以利用this.props获取组件在这里初始化它的属性,组件自己不可以自己修改props(即:props可认为是只读的)

######2,getInitialState

用于对组件的一些状态进行初始化;在以后的过程中,会再次调用,所以可以将控制控件的状态的一些变量放在这里初始化,如控件上显示的文字,可以通过this.state来获取值,通过this.setState来修改state值,一旦调用了this.setState方法,组件一定会调用render方法,React框架会自动根据DOM的状态来判断是否需要真正的渲染。

######3,componentWillMount

相当于OC中的ViewWillAppear方法.

######4,render

render是一个组件中必须有的方法,本质上是一个函数,并返回JSX或其他组件来构成DOM,和Android的XML布局类似,注意:只能返回一个顶级元素;可通过this.state和this.props数据。

######5,componentDidMount

在调用了render方法后一般会在这个函数中处理网络请求等加载数据的操作;因为UI已经成功被渲染出来,所以放在这个函数里进行请求操作,不会出现UI上的错误。

>#####***二,存在期阶段函数功能分析:***

######componentWillReceiveProps

指父元素对组件的props或state进行了修改

######shouldComponentUpdate

一般用于优化,可以返回false或true来控制是否进行渲染

######componentWillUpdate

组件刷新前调用,类似componentWillMount

######componentDidUpdate

更新后的hook

>#####***三、销毁期阶段函数功能分析:***

用于清理一些无用的内容,如:点击事件Listener,只有一个过程:componentWillUnmount

### 2.4请求网络数据:

>#####***React Native中通常是通过Ajax (异步的JavaScript和XML)请求从服务器获取数据,然后在componentDidMount方法中创建Ajax请求,等到请求成功,再用this.setState方法重新渲染UI。***

### 2.5 OC, Recat Native混合开发:

>#####***直接在iOS项目中写代码就能实现OC,reactNative混合开发,在需要引入React Native的位置引用该模块即可***

AppDelegate.m部分代码

```

jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];

RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation

moduleName:@"TGMeituan"

initialProperties:nil

launchOptions:launchOptions];

```

index.ios.js部分代码

```

AppRegistry.registerComponent('TGMeituan', () => TGMeituan);

```

xcode的代码引用了index.ios.js文件中的'TGMeituan',

index.ios.js其输出了index.ios.js定义的一个TGMeituan组件

AppDelegate.m中在合适的位置引用rootView,即可实现混合开发

```

export default class TGMeituan extends Component {

render() {

return (

);

}

}

```

### 2.6 ES5和ES6的React Native差异化:

>#####区别1:创建组件

组件是一个自定义的js对象,在es5中使用React.createClass();在es6中必须继承React.component,

>#####区别2:组件的属性props

在ES6中,其为属性:defaultProps(可以标识static定义在class内,也可以定义在class外),而在ES5中,其为方法:getDefaultProps: function(){return {name:value}};

>#####区别3:组件的状态state

上图左为ES5 ,右为ES6

### 2.7 React Native不足:

>#####组件不全,第三方组件也不全,遇到某些特殊功能,需要捣鼓很久,例如摄像相关的,文件读写,文件上传之类的组件。

>#####性能并非媲美原生,还是有一些损耗的,特别是交换大数据的时候,例如读取相册。

>#####ios和android代码并非通用,有可能会需要维护两套,或者在代码内做一些判断。

>#####并非网上大家说的,写一次代码,多端通用,网页版和客户端版完全不是一个概念,只有部分代码可重用。

>#####把代码都打包到bundle里面,不知道苹果对这种开发方式是否会不太喜欢,甚至拒绝上线。

>#####打包出来的JSBundle过大;

>#####首次进入RN页面加载缓慢;

>#####稳定性不够,有大量因为RN导致的Crash:

iOS的Crash,基本都来自RCTFatalException,都是RCTFatal抛出错误信息所知,处理也相对简单,设置自己的Error Handler即可。

void RCTSetFatalHandler(RCTFatalHandler fatalHandler);

>#####大数据量时ListView加载卡顿。

## 3.ListView重用优化

### 3.1 ListView不能重用的原因

>#####首先RN的ListView其实是基于RN的RCTScrollView来实现的。它也实现了类似UIKit中通过DataSource来控制数据,以及是否要做一些界面的刷新

>#####这个View会有一个RCTView会引用它。当这个View被移出屏幕之外,再观察他的内存引用时,它就只被RCTUIManager引用了:

>#####RN为了能够保持一定的UI上的性能,他用UImanager来管理所有的UI元素,只要创建过的,还有可能被显示在界面上的东西,他都用这个UImanager来去管理,从而在进行Dom Diff时能够减少View的创建和销毁。

###3.2 ListView多做了什么?

>#####然后,我们再来看看ListView本身比RCTScrollView多做的哪些东西,首先ListView包含两个属性—- initialListSize和pageSize,initialListSize决定了第一屏加载item的数量,pageSize则是当你需要加载更多的时候,每次需要载入多少的item,这样做的主要目的在尽量减少你手机加载第一屏时所需要的时间。

>#####还有就是它还实现了从JS端实现了Section Header,Header,Footer的封装,以及实现了监听onScroll事件,随着View的滚动动态的添加row view。

###3.3那么ListView相当于UITableView少了一点什么呢?

>#####怎么没有提到复用?


我们先看一下iOS的JS,JS里面只有一行代码

```

module.exports = require('ScrollView');

```

###3.4 ListView性能优化解决方案

Bridge一个UITableView

在RN中我们要bridge一个RN的View组件,我们需要实现RCTComponent这个protocol,这里有两个很重要的方法

- (void)insertReactSubview:(id)subview atIndex:(NSInteger)atIndex;

- (void)removeReactSubview:(id)subview;

这两个方法是RN做Dom Diff的关键

什么是Dom Diff呢

在界面发生变化前,界面存在一个Dom Tree,发生业务变化之后是另外一个Dom tree,Tree中的每个元素都有自己的引用值,Diff其实就是找出两个Tree的差异点来确定需要进行更新的节点。最终确定一个需要插入和删除的View的列表,并通知相应的Dom节点来处理。


但是RN的UI处理方式和原生对UI处理完全不一样,我们如何Bridge一个TableView呢,我们想到了一个方法。

我们创建一些VirtualView,他只是遵从了RCTComponent协议,他其实并不是一个真正的View,我把它形成一个组件,把它Bridge到JS,这就使得,你在写JSX的时候,就可以直接用VirtualView来去做布局了。在RN里面做布局的时候我们用VirtualView来做布局。但是最终在insertReactSubview时,我们把这些VirtualView当做数据去处理,通过VirtualView和RealView的对应关系,把它转化成一个真实的View对象添加到TableView中去。

用这个图来说,更清晰一些。


首先我们写的是一个JSX,React把它转化成Dom Tree,在进行Dom Diff后,React会调用insertReactSubview传入VirtualView,我们通过VirtualView生成Tree Data,

通过VirtualView和RealView的对应关系,我们创建RealView去真正的添加到原生的View上。

但是这里又产生另外一个问题,大家会自定义一个cell的一个对象来去做的。这个对象,能够接收你特定的数据,对这个cell重新去set一些控件的值,然后把界面更新。

但是在JS里面我们并没有办法这样做,在RN中,我们不可能动态的去往Native里面去加一个类。

那么我们是如何做到,在复用的时候对于Cell上面的子View能够去设置更新他的数据?


我们在所有子view上面我们也加上了tag属性,在更新数据的时候我们通过tag找到更新的子view上面的view对他做数据的更新的。所以并不是只有Cell有这样的tag,包括子view也会有这样的tag,这样就做到了可以获取到对应tag的子view并对子view的数据进行更新。


最后,为了客户端的同学在使用这个TableView时更好上手一些,我们把几乎整套的TableViewDataSource方法,全部照搬到了RN中,所以我们在创建这个ListView的时候我们需要去设置很多的回调方法,这样做也是为了能够更快的做一些界面的迁移工作。

###3.5 ListView性能优化解决方案的缺点

>#####首先既然它需要做映射,我们肯定需要做一个Virtualview到NativeView,大多数的cell里面如果做展示来用的话,Label和Image基本上能够满足大多数的需求了。所以我们现在只是做了Label和Image的对应工作,但在RN的一些官方控件,在这个view里面都是没法直接使用的。

>#####还有一个缺点就是说,因为我们是按照TableView的逻辑去做的,这个逻辑其实在Android上可能不适用,因为Android的ListView实现跟iOS完全不是一个逻辑,导致使用这个ListView的RN代码,可能没法直接应用到Android里面去。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,544评论 25 707
  • React Native优秀博客,以及优秀的Github库列表(很多英文资料源自于[awesome-react-n...
    董董董董董董董董董大笨蛋阅读 10,504评论 4 162
  • React Native 1.React Native之了解 1.1 Native开发优势: Native的原生控...
    兵兵哥哥阅读 990评论 0 1
  • React Native 1.React Native之了解 1.1 Native开发优势: Native的原生控...
    兵兵哥哥阅读 1,159评论 0 0
  • 青阳二三月,柳青桃复红。 女人把头靠着男人的肩,暖风熏得人醉。男人身上好闻的气味也让人沉醉。 沿岸桃花开得艳。游人...
    铭玥咏全阅读 275评论 0 1