@hopefrontEnd
2018-12-05T15:23:42.000000Z
字数 10042
阅读 1569
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] = arr
const obj = {a: 'x', b: 'y', c: 'z'}
const {a, b, c} = obj
我们可以在函数声明中为函数参数指定默认值。如果是,则为参数分配默认值。undefined
const printAnimal = (animal = 'cat') => {
console.log(animal)
}
printAnimal() // cat
printAnimal('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> items
in 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 export
import React from 'react-native'
// import other named exports
import {View, Text, Image} from 'react-native'
export default React
export {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() // Cat
Animal.beProud() // I AM AN ANIMAL
Class的继承
我们统计过extends
关键词简单的继承。在从父级继承的类中,我们需要使用super()
函数。在该子类的继承函数内,我们可以通过super
调用父类的函数方法
class Cat extends Animal {
printName() {
super.printName()
console.log(`My name is ${this.name}`)
}
}
修饰器
许多面向对象的语言都有修饰器(Decorator)函数,用来修改类的行为
@testable
class MyTestableClass {
// ...
}
function testable(target) {
target.isTestable = true;
}
MyTestableClass.isTestable // true
修饰器不仅可以修饰类,还可以修饰类的属性。
class Math {
@log
add(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 now
math.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 = (
<View
foo='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中图片的尺寸。
<Image
style={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