@hopefrontEnd
2018-12-05T07:23:42.000000Z
字数 10042
阅读 1764
ReactNative
使用React Native开发移动工程目前来说是十分高效的,但入门比较可能有点棘手, 本文综合笔者搭建、开发过程中的要点,难点,撰写了此篇入门指南帮助大家学习上手。 本文基本上上囊括了YDD-ReactNative开发过程中关键部分点,对陌生点给与文档指引及查看。
设置React Native开发环境有两种常用方法create-react-native-app and react-native-cli
React社区维护的一个命令行工具(Star数最高)。此工具会生成一个二维码,您可以扫描该代码以在您的设备上启动该应用。更新代码时,更改将自动反映在您的设备上。为了在您的设备上预览应用程序,系统会提示您下载应用程序,这是一个React Native应用程序预览客户端。
create-react-native-app Expo
Expo Expo类似于一个通用的SDK,提供了比较完善的UI组件和API功能, 安装时需要翻墙。
优点: 提供API较多, 开发调试环境方便。
缺点:最新的SDK只支持安卓5.0级以上,IOS10及以上,版本更新频繁。
Tips: 缺点此方式不适用于混合项目,适合纯ReactNative项目
类似Vue-cli 可以用此创建一个自定义的模版程序
一个空白的RN项目
react-native init AwesomeProject
Babel是用于预处理JavaScript的主要工具。Babel是一个高度可配置的编译器,允许您使用实验性功能和扩展,编译为可在更广泛的平台上支持的旧式JavaScript。当然,如果本机平台不支持ES6功能,Babel将无法完全提供帮助 - 但在许多情况下,polyfill缺少API以提供此功能例如Promise()。
Tips:
https://babeljs.io/repl 在线查看转换后的ES5代码
可以通过根目录中的.babelrc来配置我们的JS功能及使用的插件
RN的项目中我们主要使用了metro-react-native-babel-preset作为基本配置,并增加了@babel/plugin-proposal-decorators使用JS装饰器的功能
Tips: ReactNative 0.55以上的版本使用Babel7的版本,和以前的Babel配置有所不同具体请参考升级到Babel7
ECMAScript是用于实现JavaScript语言的语言规范。自ES5最初于2009年发布以来,ES6或ECMAScript 6是该语言的第一次重大更新。
现代JavaScript引擎中已经提供了许多ES6功能。使用Babel可以让我们访问更多功能,同时确保我们的JavaScript在更多平台上运行。React Native使用Babel启用ES6功能并确保跨平台一致性,因为您的JavaScript将在Android,iOS和其他平台上运行。
下面我将介绍一些重要的ES6使用功能点,如果想了解更多的功能可以参见ECMAScript 6 入门
let 和 const 命令
ES6 提出了两个新的声明变量的命令:let和const。其中,let完全可以取代var,因为两者语义相同,而且let没有副作用,没有变量提升的问题
const声明一个只读的常量。一旦声明,常量的值就不能改变。
函数的扩展
ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
function add(...values) {let sum = 0;for (var val of values) {sum += val;}return sum;}add(2, 5, 3)
函数的扩展
ES6 允许使用“箭头”(=>)定义函数。
可以用箭头函数来定义匿名函数,他有2个重要的属性
1. 绑定在箭头函数的外部和内部this是相同的,这和普通的函数不一样,他可以在内部调用一个其他函数
2. 函数语法可能有所不同。如果函数只接受一个参数,则可以省略括号。任何其他数量的参数都需要括号。
// 正常函数写法[1,2,3].map(function (x) {return x * x;});// 箭头函数写法[1,2,3].map(x => x * x);const numbers = (...nums) => nums;numbers(1, 2, 3, 4, 5)// [1,2,3,4,5]const headAndTail = (head, ...tail) => [head, tail];headAndTail(1, 2, 3, 4, 5)
扩展运算符
扩展运算符可以轻松扩展数组、对象。这可以用于制作数组的浅拷贝,可选地将其他元素添加到副本中。
const animals = ['cat', 'dog', 'moose']const newAnimals = [...animals]const lotsOfAnimals = [...animals, 'bear', 'mouse', 'donkey']
解构
解构是一种方便的方法,可以同时从对象或数组中提取多个键,并将值分配给局部变量。
const arr = ['one!', 'two!', 'three!', 'four!']const [one, two, ...rest] = arrconst obj = {a: 'x', b: 'y', c: 'z'}const {a, b, c} = obj
我们可以在函数声明中为函数参数指定默认值。如果是,则为参数分配默认值。undefined
const printAnimal = (animal = 'cat') => {console.log(animal)}printAnimal() // catprintAnimal('dog') // dog
$('#result').append('There are <b>' + basket.count + '</b> ' +'items in your basket, ' +'<em>' + basket.onSale +'</em> are on sale!');$('#result').append(`There are <b>${basket.count}</b> itemsin your basket, <em>${basket.onSale}</em>are on sale!`);
在ES5中,对象文字键始终被解释为字符串。ES6允许我们使用方括号语法将计算值用作对象文字中的键
const chosenAnimal = 'cat'const animals = {[`animal${chosenAnimal}`]: true,}console.log(animals.animalcat)
Module语法
与广泛使用的CommonJS模式相比,ES6提供了更高级的模块导入/导出模式。与旧版本相比,我们现在可以导出多个命名值。同样,我们可以导入多个命名值。module.exports = {...}
每个文件有一个默认导出,可以导入此导出值,而无需按名称引用它。必须命名每个其他导入和导出。
// import the default exportimport React from 'react-native'// import other named exportsimport {View, Text, Image} from 'react-native'
export default Reactexport {View, Text, Image}
Class的基本语法
ES5中,类只是函数,实例方法分配给。ES6允许我们使用更简单的语法。MyFunction.prototype class constructor`是一个特殊的函数,每次创建一个类实例时都会自动调用它。
class为我们提供了内置的实例函数,静态函数和继承。
class Animal {constructor(name) {this.name = name}static beProud() {console.log('I AM AN ANIMAL')}printName() {console.log(this.name)}}const animal = new Animal('Cat')animal.printName() // CatAnimal.beProud() // I AM AN ANIMAL
Class的继承
我们统计过extends关键词简单的继承。在从父级继承的类中,我们需要使用super()函数。在该子类的继承函数内,我们可以通过super调用父类的函数方法
class Cat extends Animal {printName() {super.printName()console.log(`My name is ${this.name}`)}}
修饰器
许多面向对象的语言都有修饰器(Decorator)函数,用来修改类的行为
@testableclass MyTestableClass {// ...}function testable(target) {target.isTestable = true;}MyTestableClass.isTestable // true
修饰器不仅可以修饰类,还可以修饰类的属性。
class Math {@logadd(a, b) {return a + b;}}function log(target, name, descriptor) {var oldValue = descriptor.value;descriptor.value = function() {console.log(`Calling ${name} with`, arguments);return oldValue.apply(this, arguments);};return descriptor;}const math = new Math();// passed parameters should get logged nowmath.add(2, 4);
我们可以使用async在一个返回值是Promise类型函数名, 在继续执行此块中的代码之前,我们可以使用关键字await等待解析或拒绝承诺
在此函数方法内我们依然可以用try catch去处理错误
const fetchData = async () => {return fetch('https://baidu.com/api/')}const printData = async () => {try {const json = await fetchData()console.log(json)} catch(e) {console.error("Problem", e)}}
一种 JavaScript 的语法扩展。 我们推荐在 React 中使用 JSX 来描述用户界面。JSX 乍看起来可能比较像是模版语言,但事实上它完全是在 JavaScript 内部实现的
JSX简介
深入JSX
const element = <h1>Hello, world!</h1>
function getGreeting(user) {if (user) {return <h1>Hello, {formatName(user)}!</h1>;}return <h1>Hello, Stranger.</h1>;}
你可以使用引号来定义以字符串为值的属性:
const element = <View tabIndex="0"/>
也可以使用大括号来定义以 JavaScript 表达式为值的属性:
const element = <Image src={user.avatarUrl}/>
切记你使用了大括号包裹的 JavaScript 表达式时就不要再到外面套引号了。JSX 会将引号当中的内容识别为字符串而不是表达式
如果 JSX 标签是闭合式的,那么你需要在结尾处用 />, 就好像 XML/HTML 一样。同时JSX也可以互相嵌套
const element = (<Viewfoo='hello'bar={baz}><Text>42</Text></View>);
Babel 转译器会把 JSX 转换成一个名为 React.createElement() 的方法调用。
上述的代码会转换如下
var a = React.createElement(View, null);var b = React.createElement(View,{foo: 'hello',bar: baz },React.createElement(Text,null,'42'))
jsx的Typescript实现称为jsx
TSX用法指南
转换路径: TSX->JSX->JS
interface Props {foo: string;}class MyComponent extends React.Component<Props, {}> {render() {return <span>{this.props.foo}</span>}}
React.Component
组件可以将UI切分成一些独立的、可复用的部件,这样你就只需专注于构建每一个单独的部件
通过声明要呈现的组件以及按什么顺序指定应用程序的整个UI。组件可以嵌套在其他组件中,形成树结构。顶级组件或树的根称为根组件,嵌套组件称为子组件。
Components在constructor实例化时的属性叫做Props,在组件上我们可以通过this.props访问属性的值,组件中我们只能Components中的方法改变Props的值。
父元素可以随时改变子元素props,子元素可以通过shouldComponentUpdate()方法订阅父元素对Props的改变。
它只是用来控制这个组件本身自己的状态,我们可以用state来完成对行为的控制、数据的更新、界面的渲染,由于组件不能修改传入的props,所以需要记录自身的数据变化。
我们可以通过this.setState()的方法去更新组件内的state。修改对象的键值的方式是无效的,我们必须要通过this.setState的方法
没有 state 的组件叫无状态组件(stateless component),设置了 state 的叫做有状态组件(stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。
以下给props和state做一个总结:
props用于定义外部接口,state用于记录内部状态
props的赋值在于外部使用组件,state的赋值在于组件内部
组件不应该改变props的值,而state存在的目的就是让组件来修改的
组件具有生命周期:它们被实例化,装载,呈现,最终更新,卸载和销毁。生命周期通过提供简单,一致的抽象层来帮助管理不同平台API(iOS,Android)的复杂性。生命周期还允许您在每个步骤中可选地执行自定义代码,以便对渲染进行更精细的控制。
让我们看一下组件生命周期的每个阶段。

组件类已实例化。构造函数的参数是元素的初始值,由父元素指定。您可以选择通过this.setState为元素指定初始状态。此时UI还没有开始绘制
在第一次进行渲染之前,此方法仅调用一次。此时,仍然UI还没有开始绘制。
render方法必须返回一个React Element来渲染(或null,以便不渲染)。
第一次渲染后,此方法仅调用一次。此时,此元素的UI绘制已完成,并且可以通过直接操作进行访问。如果您需要进行异步API调用或执行延迟代码,通常应该在此方法中完成。
指父元素对组件的props或state进行了修改
一般用于优化,可以返回false或true来控制是否进行渲染的话进行下2步操作,false不会进行下去
组件刷新前调用
render方法必须返回一个React Element来渲染(或null,以便不渲染)。
会在更新发生后立即被调用(若shouldComponentUpdate()返回false)
组件销毁阶段,例如可以在此阶段清除定时器
View
是构建RN项目最基本的元素之一,和我们编写HTML的DIV很像。不论在什么平台上,View都会直接对应一个平台的原生组件例如UIView, <div>, android.view等等。
Images
Image是用来呈现图片的容器,我们可以从资源中加载图片也可以加载网络上的图片。
在APP中加载图片我们可以选择require('./test.png')RN会自动根据设备的尺寸加载
test.png, test@2x.png, 或者test@3x.png
引入在线的web图片因为不能提前知道图片的尺寸,图片无法拉伸。所以我们在初始化的时候需要制定Image中图片的尺寸。
<Imagestyle={styles.image}source={{uri: 'http://www.reactnativeexpress.com/logo.png'}}/>const styles = StyleSheet.create({image: {width: 200,height: 200,},})
一个用于显示文本的React Native组件,并且它也支持嵌套、样式,以及触摸处理。
RN的基本布局方式,组件使用flexbox指定元素的布局。
Flexbox示例
详细的教程查看Flex布局教程
| 属性 | 默认 | 选项 | 描述 |
|---|---|---|---|
| flexDirection | column | row, column | 主轴的方向 |
| justifyContent | flex-start | flex-start, center, flex-end, space-around, space-between | 元素的横轴对齐方式 |
| alignItems | stretch | flex-start, center, flex-end, stretch | 元素的纵轴对齐方式 |
ScrollViews用于滚动元素。最好用于30个元素以下的滚动,支持横向和竖向滚动。如果有大量的元素,最好使用ListView已获得更好的性能效果
列表与ScrollViews类似,但经过优化可回收元素并减少重新渲染以获得更好的性能。因此,API比ScrollView稍微复杂一些。React Native中的内置列表组件仍在不断发展,因此将来可以期待更高的稳定性和性能。
FlatList和SectionList是简单,高性能列表的新推荐列表组件。它们构建在VirtualizedList之上,VirtualizedList是一种高度灵活和优化的列表实现,通常不应直接使用。
FlatList 继承VirtualizedList
FlatList DEMO
高性能的滚动列表组件,可用于大量可滚动内容,默认情况下每行都需要提供一个不重复的 key 属性。你也可以提供一个keyExtractor函数来生成 key。
sectionlist 继承VirtualizedList
SectionList DEMO
类似FlatList,不过提供了节标题来分隔行组。
React Native Elements
React Native Elements提供了一个跨平台的UI组件库
Tips:
1. Input用RN原生的Input组件更方便
2. 有些组件没有点击数据,需要自己在外面包装TouchableOpacity
3. 我们使用的是1.0.0 beta7版本,请不要看错文档!!!
4. React-Native-Cli工程需要react-native link react-native-vector-icons
5. 全局的样式通过theme.ts更改,更多的配置请参见ThemeProvider自定义样式
[31/webp