准备
学习React Native之前,需要了解一下其他知识,帮助你更快的理解RN
React:React中文文档
ES6:ES6入门教程
环境搭建
本人搭建的是mac+Android环境,具体过程参考:React Native中文网--搭建环境。
搭建结束后,运行项目
cd AwesomeProject
react-native run-android
当在手机或模拟器上出现如下页面,则说明配置成功。
我在搭建结束后,出现红屏,报错如下:
Unable to load script.Make sure you're either running a metro server
(run 'react-native start' ) or that
your bundle 'index.android.bundle' is packaged correctly for release.
解决方法我记录在这里:点这里。如果遇到同样的问题可以看下。
语法简介
Hello World
先看下大概长什么样
import React, { Component } from 'react';
import { Text, View } from 'react-native';
export default class HelloWorldApp extends Component {
state={ text : 'this is state.name' }
render() {
let pic = {
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
};
const stateName = this.state.name;
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Hello, world!</Text>
<Image source={pic} style={{width: 193, height: 110}} />
<Text>{stateName}</Text>
</View>
);
}
}
基本的用法Props,State等 与React是一样的,只不过基础组件不同。React里使用常规的html标签,div span等,使用了一些RN自己的原生组件Image,Text等。
样式
RN的样式与React写法页基本相同,样式名遵循了web 的css命名,只是按照JS语法要求,改成了驼峰命名。
style属性可以是简单的对象,也可以传入一个数组——在数组中位置居后的样式对象比居前的优先级更高,这样你可以间接实现样式的继承。
当样式复杂时,建议使用StyleSheet.create来集中定义组件的样式。看下例子:
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
export default class LotsOfStyles extends Component {
render() {
return (
<View>
<Text style={{color:'yellow',fontSize:'20'}}>just yellow</Text>
<Text style={styles.red}>just red</Text>
<Text style={styles.bigBlue}>just bigBlue</Text>
<Text style={[styles.bigBlue, styles.red]}>bigBlue, then red</Text>
<Text style={[styles.red, styles.bigBlue]}>red, then bigBlue</Text>
</View>
);
}
}
const styles = StyleSheet.create({
bigBlue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
StyleSheet.create可以弥补编写复杂样式时,不能使用css的不便。
宽高与布局
RN中宽高可以直接通过style指定,与web不同的是,RN中尺寸是无单位的,表示与设备像素无关的逻辑像素点。逻辑像素不清楚的,可以看这里:手机屏幕分辨率术语:逻辑分辨率和物理分辨率。
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class FixedDimensionsBasics extends Component {
render() {
return (
<View>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
</View>
);
}
}
弹性高宽
在组件样式中使用flex可以使其在可利用的空间中动态地扩张或收缩。一般而言我们会使用flex:1来指定某个组件扩张以撑满所有剩余的空间。如果有多个并列的子组件使用了flex:1,则这些子组件会平分父容器中剩余的空间。如果这些并列的子组件的flex值不一样,则谁的值更大,谁占据剩余空间的比例就更大(即占据剩余空间的比等于并列组件间flex值的比)。
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class FlexDimensionsBasics extends Component {
render() {
return (
// 试试去掉父View中的`flex: 1`。
// 则父View不再具有尺寸,因此子组件也无法再撑开。
// 然后再用`height: 300`来代替父View的`flex: 1`试试看?
<View style={{flex: 1}}>
<View style={{flex: 1, backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
</View>
);
}
}
flex box 布局
RN中flex box 的使用与web上css的flex布局用法基本一直,不同的是flex-direction默认值是column,而且RN中的flex只能是数字,而不是flex-grow, flex-shrink 和 flex-basis的简写。
一般来说,使用flexDirection、alignItems和 justifyContent三个样式属性就已经能满足大多数布局需求。
例如:
export default class JustifyContentBasics extends Component {
render() {
return (
// 尝试把`justifyContent`改为`center`看看
// 尝试把`flexDirection`改为`row`看看
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'space-between',
}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
</View>
);
}
};
注意:RN中flexbox不需要一定指定flex:1,只要外层元素高度存在(可以设置height),设置flexDirection、alignItems或 justifyContent,内部元素都会根据样式规则,遵循Flexbox布局。
事件响应
RN事件响应的写法,与ReactJS类似。不同的是,移动端手势的响应要比web端复杂的多,RN通过响应者的声明周期,来响应不同触摸事件。
响应者的生命周期
我们通过两个方法去“询问”一个 View 是否愿意成为响应者:
- View.props.onStartShouldSetResponder: (evt) => true, - 在用户开始触摸的时候(手指刚刚接触屏幕的瞬间),是否愿意成为响应者?
- View.props.onMoveShouldSetResponder: (evt) => true, - 如果 View 不是响应者,那么在每一个触摸点开始移动(没有停下也没有离开屏幕)时再询问一次:是否愿意响应触摸交互呢?
如果View 返回 true,并开始尝试成为响应者,那么会触发下列事件之一:
- View.props.onResponderGrant: (evt) => {} - View 现在要开始响应触摸事件了。这也是需要做高亮的时候,使用户知道他到底点到了哪里。
- View.props.onResponderReject: (evt) => {} - 响应者现在“另有其人”而且暂时不会“放权”,请另作安排。
如果 View 已经开始响应触摸事件了,那么下列这些处理函数会被一一调用:
- View.props.onResponderMove: (evt) => {} - 用户正在屏幕上移动手指时(没有停下也没有离开屏幕)。
- View.props.onResponderRelease: (evt) => {} - 触摸操作结束时触发,比如"touchUp"(手指抬起离开屏幕)。
- View.props.onResponderTerminationRequest: (evt) => true - 有其他组件请求接替响应者,当前的 View 是否“放权”?返回 true 的话则释放响应者权力。
- View.props.onResponderTerminate: (evt) => {} - 响应者权力已经交出。这可能是由于其他 View 通过onResponderTerminationRequest请求的,也可能是由操作系统强制夺权(比如 iOS 上的控制中心或是通知中心)。
class App extends Component<Props> {
onStartShouldSetResponder = () => {
console.log("onStartShouldSetResponder");
return false;
};
onMoveShouldSetResponder = () => {
console.log("onMoveShouldSetResponder");
return false;
};
onResponderMove = eve => {
console.log("onResponderMove", eve);
};
onResponderGrant = eve => {
console.log("onResponderGrant", eve);
};
onResponderReject = eve => {
console.log("onResponderReject", eve);
};
pressIt = eve => {
console.log("onPress");
};
render() {
return (
<View style={styles.container}>
<View
onResponderMove={this.onResponderMove}
onStartShouldSetResponder={this.onStartShouldSetResponder}
onResponderReject={this.onResponderReject}
onResponderGrant={this.onResponderGrant}
onMoveShouldSetResponder={this.onMoveShouldSetResponder}
style={{
height: 50,
width: 50,
backgroundColor: "#ccc",
cursor: "pointer"
}}
>
<Text>点我!</Text>
</View>
)
}
生命周期的执行顺序,可以实际触发试试。
Touchable系列组件
- 一般来说,你可以使用TouchableHighlight来制作按钮或者链接。注意此组件的背景会在用户手指按下时变暗。
- 在 Android 上还可以使用TouchableNativeFeedback,它会在用户手指按下时形成类似墨水涟漪的视觉效果。
- TouchableOpacity会在用户手指按下时降低按钮的透明度,而不会改变背景的颜色。
- 如果你想在处理点击事件的同时不显示任何视觉反馈,则需要使用TouchableWithoutFeedback。
滚动视图与长列表
滚动视图
ScrollView是一个通用的可滚动的容器,你可以在其中放入多个组件和视图,而且这些组件并不需要是同类型的。ScrollView 不仅可以垂直滚动,还能水平滚动(通过horizontal属性来设置)。
export default class IScrolledDownAndWhatHappenedNextShockedMe extends Component {
render() {
return (
<ScrollView>
<Text style={{fontSize:96}}>Scroll me plz</Text>
<Image source={{uri: "https://facebook.github.io/react-native/img/favicon.png", width: 64, height: 64}} />
<Image source={{uri: "https://facebook.github.io/react-native/img/favicon.png", width: 64, height: 64}} />
<Image source={{uri: "https://facebook.github.io/react-native/img/favicon.png", width: 64, height: 64}} />
<Image source={{uri: "https://facebook.github.io/react-native/img/favicon.png", width: 64, height: 64}} />
<Image source={{uri: "https://facebook.github.io/react-native/img/favicon.png", width: 64, height: 64}} />
<Text style={{fontSize:96}}>If you like</Text>
)
}
ScrollView内部所有组件都会被渲染,即使这些组件在屏幕的外部。如果要显示较长滚动内容,建议使用性能更好的长列表组件:FlatList。
长列表
长列表常用的组件有FlatList和SectionList。
FlatList用法
- 用于显示一个垂直的滚动列表,其中的元素之间结构近似而仅数据不同
- 更适于长列表数据,且元素个数可以增删。FlatList并不立即渲染所有元素,而是优先渲染屏幕上可见的元素。
- FlatList组件必须的两个属性是data和renderItem。data是列表的数据源,而renderItem则从数据源中逐个解析数据,然后返回一个设定好格式的组件来渲染。
export default class FlatListBasics extends Component {
render() {
return (
<View style={styles.container}>
<FlatList
data={[
{key: 'Devin'},
{key: 'Jackson'},
{key: 'James'},
{key: 'Joel'},
{key: 'John'},
{key: 'Jillian'},
{key: 'Jimmy'},
{key: 'Julie'},
]}
renderItem={({item}) => <Text style={styles.item}>{item.key}</Text>}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 22
},
item: {
padding: 10,
fontSize: 18,
height: 44,
},
})
SectionList的用法
SectionList与FlatList相似,只不过多了一个分组功能。
export default class SectionListBasics extends Component {
render() {
return (
<View style={styles.container}>
<SectionList
sections={[
{title: 'D', data: ['Devin']},
{title: 'J', data: ['Jackson', 'James', 'Jillian', 'Jimmy', 'Joel', 'John', 'Julie']},
]}
renderItem={({item}) => <Text style={styles.item}>{item}</Text>}
renderSectionHeader={({section}) => <Text style={styles.sectionHeader}>{section.title}</Text>}
keyExtractor={(item, index) => index}
/>
</View>
);
}
}
网络请求
React Native 提供了和 web 标准一致的Fetch API,用于满足开发者访问网络的需求。
Fetch的第一个参数用来指定请求路径,可选的第二个参数,可以指定http一些请求参数。
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
}),
});
Fetch返回一个Promise对象,RN中可以使用promise这样获取数据:
fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
return responseJson.movies;
})
.catch((error) => {
console.error(error);
});
也可以使用async/await
let response = await fetch(
'https://facebook.github.io/react-native/movies.json',
);
let responseJson = await response.json();
return responseJson.movies;
除了Fetch之外也可以使用frisbee和axios等其他网络库。
React Native的优缺点
RN的语法先介绍到这里,详细的用法可以看这个React Native中文网。
在具体的使用之前,我们了解下RN的优劣势,来判断是否需要用它。
简单介绍下RN的优劣势,来决定是否需要用它。
优点
- 调试方便
RN支持hotReload以及liveReload,在调试界面的时候非常方便,修改代码之后保存,界面就自动跟着变化。也可以使用chrome,react-devtools调试。 - 跨平台开发,可以写一套代码,Android和ios并行开发。
- 使用热更新,便于维护快速更迭的模块,跳过漫长的App审核。
缺点
-
长列表及动画性能不佳
长列表快速向上滚动时,列表会出现白屏的情况,RN的动画会出现卡顿问题。这两个问题基本是因为js与native频繁通信造成的,很难从根本上解决。
- 版本更新快,项目中更新一次RN,对代码改动较大,很耗时。
- 两个平台还没有完全统一,一些控件在两个平台变现会有差异。
Flutter,比RN更好的跨平台方案?
在实际工作中RN一般作为原生开发的补充,来开发一些快速迭代的页面,但很难取代原生开发,成为App开发的最优解。Flutter作为目前炙手可热的跨平台方案,能否取代RN,Weex,还不能确定。首先我们先简单了解下Flutter。
React-Native、Weex 核心是通过 Javascript 开发,执行时需要 Javascript 解释器,UI 是通过原生控件渲染。Flutter 与用于构建移动应用程序的其它大多数框架不同,因为 Flutter 既不使用 WebView,也不使用操作系统的原生控件。 相反,Flutter 使用自己的高性能渲染引擎来绘 制 widget。
它的开发语言是Dart,Dart是面向对象的,类定义的,单继承语言,语法类似c语言,可以转义为js。
Flutter特点:
- 快速开发
由于Flutter选用了Dart作为其开发语言,Dart既可以是AOT(Ahead Of Time)编译,也可以是JIT(Just In Time)编译,其JIT编译的特性使Flutter在开发阶段可以达到亚秒级有状态热重载,从而大大提升了开发效率。但是Flutter不支持代码的热更新。 - 性能优越
使用自带的高性能渲染引擎(Skia)进行自绘,渲染速度和用户体验堪比原生。 - UI 一致性
Flutter 因为是自己做的渲染,因此在iOS和Android的效果基本完全一致。React Native存在将RN控件转换为对应平台原生控件的过程,存在一定的差异(如Button在iOS和Android下面显示效果不一样)。 - App体积
Flutter iOS空项目 30M左右,Android空项目 7M左右 (iOS需要额外集成Skia)。 React Native iOS空项目 3M左右,Android20M左右(Android会加入OKHttp导致体积增大)。
具体flutter介绍可以看下:
移动跨平台框架Flutter介绍和学习线路
如何评价 Google 的 Fuchsia、Android、iOS 跨平台应用框架 Flutter?
此外作为 Fuchsia OS 的正统 app framework,Flutter的应用前景,与Fuchsia的推广程度息息相关。可以看下知乎对Fuchsia和Flutter的讨论:
如何看待 Google 的新操作系统 Fuchsia?
Flutter 在 2019 年会有怎样的表现
总结
React Native语法和基本用法与ReactJs类似,之前用过React的,RN上手很快。虽然RN在性能上和跨平台一致性等方面算不上完善,但目前在国内主流大厂,RN仍是最常用的跨平台解决方案之一。对于日常工作中可能会用到技术,花时间学学还是很必要的。即使Flutter真的取代了RN,Flutter的React 风格,也会让熟悉RN开发的同学更好上手。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。