接触React-Native有一段时间了,本篇博客讲下我对RN的理解,以及入门RN必须要了解的一些基础知识。文中也会贴上一些我认为写得很好的博客链接,也是对自己学习的知识一个总结。话不多说,直接开始吧。
React特点
说到RN,首先要讲React,React是facebook2013年出来的一个新产物。2013年有了RN的ios版,但直到2015年有了RN for android,RN用在移动开发中才开始火起来。入门React.js可以看下这个链接React入门实战教程。那么React有什么特点呢,下面大概说一下。
虚拟DOM
提到React最先想到的就是虚拟DOM。因为这个想法实现是太好了。简而言之就是,React中UI界面是一棵DOM树,对应的我们创建一个全局唯一的数据模型,每次数据模型有任何变化,都将整个数据模型应用到UI DOM树上,由React来负责去更新需要更新的界面部分。
传统的DOM比较需要一个节点一个节点比,时间复杂度是O(N3),React 通过分层求异的策略,对 tree diff 进行算法优化,简单说,这种虚拟DOM算法是同级的进行比较,并不进行跨层级比较,所以比较一次只需要O(N)的时间,效率非常高。当然这种情况下如果你对组件进行跨层级的移动,虚拟DOM会认为是删除了一个组件而新建了一个组件,会影响效率,所以开发中一般不进行跨层次的移动组件。
此外,React对同层级的比较中通过设置唯一 key的策略来优化了比较策略,大大的提高了效率,具体的看下下面这篇博客不可思议的react diff,写得很清楚。这里就不再赘述。
JSX定义界面
JSX是React的核心组成部分,它使用XML标记的方式去直接声明界面,将HTML直接嵌入到JavaScript代码中。看下示例代码:
var React = require(‘React’);
var message =
<div class=“hello”>
<span>Hello World</span>
</div>;
React.renderComponent(message, document.body);
很奇怪的写法。但是确很直观,开发起来也很快。不需要过多考虑模板的概念,只需要考虑如何用代码构建整个界面。
单向数据流
React本身只是View层,对于事件传输层FB建议使用Flux这种单向传输架构。Flux 是一种架构思想,它分为View(视图层)、Action(动作)、Dispatcher(派发器)、Store(数据层)四层。数据流的流向参考下图:
首先用户访问 View,并通过View 发出用户的 Action。Dispatcher 接到Action后就要求 Store 进行相应的更新。store更新后会发一个事件到View上,最后View更新页面。简单的理解可以认为它是一种全局的消息发布订阅模型。Action可以来自于用户的某个界面操作,比如点击等;也可以来自服务器端的网络返回。当数据模型发生变化时,就触发刷新整个界面。
看下这篇文章Flux架构入门。在RN中用的比较多的Flux框架是Redux。之后可能会写专门博文总结下它,可以看这个链接进行学习Redux自述。
独特的数据模型
React的所有数据都是只读的,如果需要修改它,那么你只能产生一份包含新的修改的数据。这样做是为了让代码更加的安全和易于维护。React将用户界面看做简单的状态机器。当组件处于某个状态时,那么就输出这个状态对应的界面。在React中,只要简单的去更新某个组件的状态,React就公以最高效的方式去比较两个界面并更新DOM树。
React-Native生命周期
与Activity类似,RN也有自己的生命周期。先看下我在网上找的一张生命周期图,很完整:
下面分点讲下各种方法:
- getDefaultProps:在组件创建之前,会先调用 getDefaultProps(),这是全局调用一次。在组件被创建前加载。
- getInitialState(),来初始化组件的状态。
- componentWillMount:准备开始加载组件。在整个生命周期中只被调用一次,可以在这里做一些业务初始化操作,也可以设置组件状态。
- componentDidMount:在组件第一次绘制之后调用,这个函数调用的时候,其虚拟 DOM 已经构建完成,你可以在这个函数开始获取其中的元素或者子组件了。需要注意的是,RN 框架是先调用子组件的 componentDidMount():然后调用父组件的函数。从这个函数开始,就可以和 JS 其他框架交互了,例如设置计时 setTimeout 或发起网络请求。这个函数之后,就进入了稳定运行状态,等待事件触发。
- componentWillReceiveProps:如果组件收到新的props,就会调用 componentWillReceiveProps(),在这个回调函数里面,你可以根据属性的变化,通过调用 this.setState() 来更新你的组件状态,这里调用并不会触发额外的 render() 调用。
- shouldComponentUpdate:当组件接收到新的属性和状态改变的话,都会触发调用 shouldComponentUpdate(…),这个函数的返回值决定是否需要更新组件,如果 true 表示需要更新,继续走后面的更新流程。否者,则不更新,直接进入等待状态。
- componentWillUpdate:如果组件状态或者属性改变,并且上面的 shouldComponentUpdate(…) 返回为 true,就会开始准更新组件,并调用 componentWillUpdate(),在这个回调中,可以做一些在更新界面之前要做的事情。需要特别注意的是,在这个函数里面,你就不能使用 this.setState 来修改状态。紧接着这个函数,就会调用 render() 来更新界面了
- componentDidUpdate调用了 render() 更新完成界面之后,会调用 componentDidUpdate() 来得到通知。
- componentWillUnmount当组件要被从界面上移除的时候,就会调用 componentWillUnmount()。在这个函数中,可以做一些组件相关的清理工作,例如取消计时器、网络请求等。
React-Native的JSX用法
'use strict'
import React,{
Image,
StyleSheet,
Text,
View,
Dimensions,
} from 'react-native';
var GuideActivity = require('./js/GuideActivity');
var SplashScreen = React.createClass({
getInitialState: function() {
return {
cover: null,
};
},
componentDidMount: function() {
....
},
render: function() {
var img, text;
img = require('./../guide.jpg');
text = 'srdb';
return(
<View style={styles.container}>
<Text style={styles.text}>
{text}
</Text>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
text: {
flex: 1,
fontSize: 16,
textAlign: 'center',
color: 'white',
position: 'absolute',
left: 0,
right: 0,
bottom: 10,
backgroundColor: 'transparent',
}
});
module.exports = SplashScreen;
以上就是最简单的jsx代码。麻雀虽小,五脏俱全。
import React,{
Image,
StyleSheet,
Text,
View,
Dimensions,
} from 'react-native';
上面代码用于声明要用到的组件,如用到View,Text组件就要手动导入。这里声明的是系统己有的组件。
var GuideActivity = require('./js/GuideActivity');
上面代码用于导入你自己Js文件,GuideActivity 相当于是一个组件。
var SplashScreen = React.createClass({
render: function() {
return(
);
}
});
上面是必不可少的代码,你写的界面渲染就在render里面。Jsx语法就是遇到xml以()包括起,遇到js代码以{}括起。如果需要初始化等,就在React.createClass中调用相应的生命周期函数。看上面代码。
<View style={styles.container}>
<Text style={styles.text}>
{text}
</Text>
</View>
上面就是布局,结构的语就是html写的,RN与react.js不同的是,react是DOM操作,RN是组件操作。View,Text都是组件。样式的话用定义如下:
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
});
最后导出你写的组件。
module.exports = SplashScreen;
这样就可以在其它文件中引用了。
先写到这吧。接下来博客会更新一些RN相关的知识。