React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的UI框架 React 在原生移动应用平台的衍生产物,目前支持iOS和安卓两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。
一、从 ES6 开始
-
const、let 关键字
let:众所周知 JavaScript 中变量默认是全局的,只存在函数级作用域。ES6中提出 let 关键字,使JavaScript 也有了块级作用域。
-
const:用来定义常量,一旦定以后不可修改,但是可以修改属性。
const MYNAME = {foo: 'Ginger'}; MYNAME.foo = 'Zoe';
-
函数
-
箭头函数
可以看做是一种语法糖,箭头函数永远是匿名的let add = (a, b) => {return a + b;} // 当后面是表达式的时候,还可以简写成 let add = (a, b) => a + b; // 等同于 let add = function(a, b){ return a + b; } // 在回调函数中的应用 let numbers = [1, 2, 3]; let doubleNumbers = numbers.map((number) => number * 2); // [2, 4, 6]
-
this 在箭头函数中的使用
在对象方法的嵌套函数中,this 会指向 global。let age = 2; let kitty = { age: 1, grow: function() { setTimeout(function() { console.log(++this.age); }, 100); } } kitty.grow(); // 3 // 一般的解决方法 let kitty = { age: 1, grow: function() { setTimeout(function() { console.log(++this.age); }.bind(this), 100); } } // 或者 let kitty = { age: 1, grow: function() { const self = this; setTimeout(function() { console.log(++self.age); }.bind(this), 100); } } // 有了箭头函数这个问题就可以轻松解决了 let kitty = { age: 1, grow: function() { setTimeout(() => { console.log(++this.age); }, 100); } }
-
默认参数函数
function desc(name = 'Ginger', age = 18){ return name + ' is ' + age + ' years old'; } desc(); //Ginger is 18 years old
-
Rest 参数
当一个函数的最后一个参数有“…”这样的前缀,它就会变成一个参数的数组。function test(...args){ console.log(args); } test(1, 2, 3); //[1, 2, 3] function test2(name, ...args){ console.log(args); } test2('Ginger', 2, 3); //[2, 3]
-
-
展开操作符(“…”)
允许一个表达式在某处展开,在存在多个参数(用于函数调用)、多个元素(用于数组字面量)或者多个变量(用于结构赋值)的地方就会出现这种情况。
-
用于函数调用
// 之前,想让函数把一个数组作为依次作为参数调用方法如下 function test(x, y, z) { }; var args = [1, 2, 3]; test.apply(null, args); // 有了 ES6 的展开运算符之后 function test(x, y, z) { }; let args = [1, 2, 3]; test(...args);
-
用于数组字面量
在之前的版本中,想要创建含某些元素的新数组,常使用 splice、concat、push.var arr1 = [1, 2, 3]; var arr2 = [4, 5, 6]; var arr3 = arr1.concat(arr2); // 使用 ES6 之后 let arr1 = [1, 2, 3]; let arr2 = [4, 5, 6]; let arr3 = [...arr1, ...arr2];
-
对象的展开运算符
let mike = {name: 'mike', age: 50}; mike = {...mike, sex: 'male'}; console.log(mike); // {name: 'mike', age: 50, sex: 'male'}
-
-
模板字符串(注意不是',是`)
字符串拼接总是令人很不爽的一件事情,但是在 ES6 来临的时代,这个痛处也被治愈了。// 之前 var name = 'Ginger'; var a = 'My name is ' + Ginger + '!' // 多行 var langStory = 'This is a long story,' + 'this is a long story,' + 'this is a long story.'; // 有了 ES6 之后 let name = 'Ginger'; let a = `My name is ${name} !`; let longStory = `This is a long story, this is a long story, this is a long story`;
-
解构赋值
-
解构数组
let foo = ['one', 'two', 'three']; let [one, two, three] = foo; console.log(`${one}, ${two}, ${three}`); // one, two, three
-
解构对象
let person = {name: 'Ginger', age: 18}; let {name, age} = person; console.log(`${name}, ${age}`); // Ginger, 18
-
-
类
提供了 class 这个语法糖。让开发者可以模仿其他语言类的声明方式。只是原型链方式的一种语法糖。class Animal { // 构造函数 constructor (name, age) { this.name = name; this.age = age; } shout() { return `${name}, ${age}`; } // 静态方法 static foo() { return 'here is a static method'; } } const cow = new Animal('betty', 2); cow.shout(); // betty, 2 Animal.foo(); // here is a static method class Dog extends Animal { constructor(name, age = 2, color = 'black') { // 在构造函数中可以直接调用 spuer 方法 super(name, age); this.color = color; } shout(){ // 非构造函数中不能直接调用 super 方法 return `${name}, ${age}, ${color}`; } }
模块
在 ES6 之前,JavaScript 并没有对模块做出任何定义,于是先驱者们创造了各种各样的规范来完成这个任务。比如 Require.js,CommonJS,browerify 等等。
使用 import export 关键字来完成模块的导入和导出。
还可以使用 default 关键字来默认导出。
二、再说说 React
特点:1. 组件化;2. JSX;3. 虚拟 DOM;
-
JSX
-
JSX 不是必须的。类似一种语法糖。把标签型的写法转化成 React 提供的一个用来创建 ReactElement 的方法。
let app = <h1 title = "My title">this is my title</h1> // jsx转换后的结果 let app = React.createElement('h1', {title: 'my title', 'this is my title'});
HTML 标签与 React 组件
HTML 标签第一个字母用小写表示。
React 组件第一个字母用大写表示。
JSX 语法使用第一个字母大小写来区分是一个普通的 HTML 标签还是一个 React 组件。JavaScript 表达式
当遇到{}这个表达式的情况下,里面的代码会被仿作 JavaScript 代码处理。
当省略一个属性值的时候,JSX会自动把它的值认为是 true。-
注释
JSX 注释沿用 JavaScript 的方法,需要注意的是,在子组件的位置需要用{}括起来。let component = ( <div> {/*这里是一个注释!*/} <Headline /> </div> );
-
JSX 属性扩散
let props = { name: 'Ginger', age: 18 } // 用这种方式可以将 name,age 全部载入进来 let component = <Profile {...props} /> // 值得注意的是,越靠后的属性会覆盖前面的属性 let component = <Profile {...props} name='Zoe' />
-
-
React 的生命周期
实例化
首次实例化
- getDefaultProps
- getInitialState
- componentWillMount
- render
- componentDidMount
实例化完成后的更新
- getInitialState
- componentWillMount
- render
- componentDidMount
存在期
组件已存在时的状态改变
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
销毁&清理期
- componentWillUnmount
说明
生命周期共提供了10个不同的API。
1.getDefaultProps
作用于组件类,只调用一次,返回对象用于设置默认的
props
,对于引用值,会在实例中共享。2.getInitialState
作用于组件的实例,在实例创建时调用一次,用于初始化每个实例的
state
,此时可以访问this.props
。3.componentWillMount
在完成首次渲染之前调用,此时仍可以修改组件的state。
4.render
必选的方法,创建虚拟DOM,该方法具有特殊的规则:
- 只能通过
this.props
和this.state
访问数据 - 可以返回
null
、false
或任何React组件 - 只能出现一个顶级组件(不能返回数组)
- 不能改变组件的状态
- 不能修改DOM的输出
5.componentDidMount
真实的DOM被渲染出来后调用,在该方法中可通过
this.getDOMNode()
访问到真实的DOM元素。此时已可以使用其他类库来操作这个DOM。比如 AJAX 请求可以放在这里。在服务端中,该方法不会被调用。
6.componentWillReceiveProps
组件接收到新的
props
时调用,并将其作为参数nextProps
使用,此时可以更改组件props
及state
。componentWillReceiveProps: function(nextProps) { if (nextProps.bool) { this.setState({ bool: true }); } }
7.shouldComponentUpdate
组件是否应当渲染新的
props
或state
,返回false
表示跳过后续的生命周期方法,通常不需要使用以避免出现bug。在出现应用的瓶颈时,可通过该方法进行适当的优化。在首次渲染期间或者调用了forceUpdate方法后,该方法不会被调用
8.componentWillUpdate
接收到新的
props
或者state
后,进行渲染之前调用,此时不允许更新props
或state
。9.componentDidUpdate
完成渲染新的
props
或者state
后调用,此时可以访问到新的DOM元素。不能再该状态下 setState 等,会造成组件死循环。10.componentWillUnmount
组件被移除之前被调用,可以用于做一些清理工作,在
componentDidMount
方法中添加的所有任务都需要在该方法中撤销,比如创建的定时器或添加的事件监听器。 -
组件
先来一个简单的例子。import React from 'react'; class List extends React.Component { // 在 ES6 中不再使用getInitialState而使用constructor constructor(props) { super(props); this.state = ['a', 'b', 'c']; } render(){ return (...); } }
props 属性
可以看做是组件的数据来源。
要想子组件传递数据需要通过 props 来完成state 状态
state 是组件内部的属性。
当 state 的值发生改变的时候,可以调用 this.setState 方法让组件再次调用 render 方法,重新渲染 UI。
state 中应该包含组件的事件回调函数可能引发 UI 更新的这类数据。-
引入组件
将组件的文件引入,再在新的组件中加入已经写好的组件标签。import React from 'react'; import List from './list'; class Profile extends React.Component { // 在 ES6 中不再使用getInitialState而使用constructor constructor(props) { super(props); } render(){ return ( <List /> ); } }
三、让我们开始 React Native 的旅程
快速开始
参考网站:http://reactnative.cn/docs/0.41/getting-started.html
事先搭建好开发环境。快速开始:react-native init HelloRN
进入这个 HelloRN 文件夹后,里面有两个入口文件: index.ios.js index.android.js,修改入口文件内容刷新模拟器,即可看到你写的内容~-
flexbox 布局
我们在React Native中使用flexbox规则来指定某个组件的子元素的布局。Flexbox可以在不同屏幕尺寸上提供一致的布局结构。
一般来说,使用flexDirection
、alignItems
和justifyContent
三个样式属性就已经能满足大多数布局需求。
摘自网上总结的很好的 flex 布局口诀图。(http://weibo.com/1712131295/CoRnElNkZ?ref=collection&type=comment#_rnd1488247287265)
-
常用组件介绍
入口文件说明import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, View } from 'react-native'; // 将使用到的 react-native 组件引入 export default class reactNative extends Component { render() { return ( // View 组件相当于 html 的 div。可以视作一个包裹内容的容器。 <View style={styles.container}> // 所有的文字内容都需要被包裹在 Text 标签中 <Text style={styles.welcome}> Welcome to React Native! </Text> // 若要直接在组件中写入样式 <Text style={{textAlign: 'center'}}>。注意是 {{}} <Text style={styles.instructions}> To get started, edit index.ios.js </Text> <Text style={styles.instructions}> Double tap R on your keyboard to reload,{'\n'} Shake or press menu button for dev menu </Text> </View> ); } } // StyleSheet提供了一种类似CSS样式表的抽象。RN 中样式使用驼峰格式。 const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, }); AppRegistry.registerComponent('reactNative', () => reactNative); // AppRegistry是JS运行所有React Native应用的入口。应用的根组件应当通过AppRegistry.registerComponent方法注册自己,然后原生系统才可以加载应用的代码包并且在启动完成之后通过调用AppRegistry.runApplication来真正运行应用。
View
类似于 html 中的 div,盒子布局,将内容包裹在里面。Text
所有的文字都必须要放在 Text 标签中。Image
renderImages() { return ( <View> // 本地模式 <Image style={styles.icon} source={require('./icon.png')} /> // 使用网络资源 <Image style={styles.logo} source={{uri: 'http://facebook.github.io/react/img/logo_og.png'}} /> </View> ); }
至此,关于 React Native 的基础说明完成。赶快开始在 index.ios.js 中涂涂画画吧~
-
其他常用组件
-
NavigatorIOS
该组件本质上是对 UIKit navigation 的包装。也就是说,使用 NavigatorIOS 进行路由切换,实质上是调用了UIKit的navigation。
TextInput
通过键盘将文本输入到 app 的组件。Touchable
RN 没有像 web 开发那样可以个元素绑定 click 时间。Text 组件中可以使用 onPress 事件绑定触摸点击事件。为了使其他组件也可以被点击,提供了3个组件来做这个事情。这3个组件被称为“Touchable类组件”。-
TarBarIOS
为切换不同页面
WebView
-
赶快动手试试这些组件吧~
参考内容:
http://reactnative.cn/docs/0.41/getting-started.html
《React 全栈》
《React Native 入门与实战》