1.React Native组件
独立的、可重用的模块。
有3种方式可以创建组件:1. ES6方式创建;2. ES5方式创建;3.函数式定义无状态组件方式
// ES6方式创建组件
type Props = {};
export default class App extends Component<Props> {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To get started, edit App.js</Text>
<Text style={styles.instructions}>{instructions}</Text>
</View>
);
}
}
// ES5方式创建组件
var App = React.createClass({
render(){
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To get started, edit App.js</Text>
<Text style={styles.instructions}>{instructions}</Text>
</View>
);
}
})
module.exports = App;
// 无状态组件方式:没有this,没有生命周期函数
function App(){
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To get started, edit App.js</Text>
<Text style={styles.instructions}>{instructions}</Text>
</View>
);
}
module.exports = App;
2.React Native组件生命周期
React Native使用React语法,与React组件拥有一样的生命周期函数,
分为3种状态:
Mounting:挂载,已插入真实Dom
Updating:更新,正在被重新渲染
Unmounting:卸载,已移出真实Dom
4个阶段
创建:只调用getDefaultProps
方法
实例化:getInitialState
,componentWillMount
,render
(渲染并返回一个虚拟Dom),componentDidMount
(根据虚拟Dom对象创建真实Dom,可以在此获取Dom节点)
更新:static getDerivedStateFromProps(props, state)
;shouldComponentUpdate(nextProps, nextState)
;render()
;getSnapshotBeforeUpdate(props, state)
;componentDidUpdate(preProps, preState, snapshot)
销毁:componentWillUnmount
3.组件的导入与导出
// ES6:export导出,import导入
// 导出
export default class App extends Component{
render() {
return (
<Text style={styles.welcome}>Welcome to React Native!</Text>
);
}
}
// 导入
import App from './App';
// ES5: module.export导出,import导入
// 导出
var App = React.createClass({
render(){
return (
<Text style={styles.welcome}>Welcome to React Native!</Text>
);
}
})
module.exports = App;
//导入
import App from './App';
4.props
React相当于MVC的View层,负责展示,并不涉及到数据,但是组件在使用的过程中有两个属性是和数据有关的:props和state
props:组件自身的属性,一般用于嵌套的内外层组件中,由父组件传给子组件,负责传递信息,也可以用于属性约束和验证。(props对象中的属性与组件属性一一对应--除this.props.children之外,不要直接修改props属性中的值)
...this.props:可以将父组件中传递的全部属性复制给子组件
this.props.children:组件的所有子节点。它的返回值可以是任意类型的,所以用它来处理一些东西的时候很不方便,好在React的React.Children提供了处理this.props.children的一些方法:React.Children.map()
,React.Children.forEach()
,React.Children.count()
,React.Children.only()
,React.Children.toArray()
,通常与React.cloneElement()
结合使用来操作this.props.children。
属性验证:定义外部组件(父组件)传递的属性值类型是否符合组件定义的类型要求(一般在通用组件定义时使用)
propsTypes:在React15.5之前可以通过React.PropTypes 进行属性验证,之后我们需要借助
prop-types
库。
// 1.引入 prop-types 库
npm install --save prop-types
// 2.导入prop-types
import PropTypes from 'prop-types';
// 3.定义子组件
export default class PropsTest extends Component{
// 设置props的默认值
static defaultProps={ name: 'xiao ming', age: 18, gender: 'man'}
//约束的关键就是这里在定义属性的时候指定属性的类型,类似安卓private String name;
static propTypes={
name: PropTypes.string,
age: PropTypes.number,
gender: PropTypes.string.isRequired
}
render(){
//在这里我们使用props中的name属性
return (
<Text>
{this.props.name}+' age:'+{this.props.age}+' gender:'+{this.props.gender}
</Text>
)
}
}
// 4.定义父组件,并在父组件中调用子组件
export default class HomePage extends Component{
render(){
const params = { name: 'daming', age: 20, gender: 'man' }
return <PropsText {...params}/>
}
}
5.state
我们使用两种数据来控制一个组件:props和state。props是在父组件中指定,而且一经指定,在被指定的组件的生命周期中则不再改变。 对于需要改变的数据,我们需要使用state。state 的工作原理和 React.js 完全一致。
一般来说,你需要在 constructor 中初始化state(译注:这是 ES6 的写法,早期的很多 ES5 的例子使用的是 getInitialState 方法来初始化 state,这一做法会逐渐被淘汰),然后在需要修改时调用setState方法,每次调用setState都会重新调用组件render()方法。有几个点需要注意:
- 一切界面变化都是状态state变化
- state的修改必须通过setState()方法
- setState 是一个 merge 合并操作,只修改指定属性,不影响其他属性
- setState 是异步操作,修改不会马上生效,要获取到新设置的state属性,需要在setState的回调函数中
export default class StateTest extends Component{
// 设置state的默认值
state = {
name: '小红',
age: 16,
gender: 'women',
};
render(){
return (
<Text>
{this.state.name}+' age:'+{this.state.age}+' gender:'+{this.state.gender}
</Text>
)
}
}
6.ref
父组件获取子组件的属性
// 子组件
export default class RefTest extends Component{
// 设置state的默认值
state = { name: '小白' };
getName(){
return this.state.name;
}
render(){
return (
<Text>
哈哈哈
</Text>
)
}
}
// 父组件
import RefTest from './RefTest';
export default class RefFather extends Component{
render(){
return (
<View>
<Text>
你好,{this.refTest.getName()}!
</Text>
<RefTest ref ={refTest => this.refTest=refTest} />
</View>
)
}
}
7.样式
在 React Native 中,你并不需要学习什么特殊的语法来定义样式。我们仍然是使用 JavaScript 来写样式。所有的核心组件都接受名为style的属性。这些样式名基本上是遵循了 web 上的 CSS 的命名,只是按照 JS 的语法要求使用了驼峰命名法,例如将background-color改为backgroundColor。
style属性可以是一个普通的 JavaScript 对象,还可以传入一个数组——在数组中位置居后的样式对象比居前的优先级更高,这样可以间接实现样式的继承。
定义样式
- HTML5以 ‘;’ 结尾
RN 以 ‘,’ 结尾- HTML5的key、value都不加引号
RN中属于js对象,key的名字不能出现‘-’,要使用驼峰命名法;如果value为字符串,需要加引号- HTML5中,value如果是数字,需要加单位
RN中,value是数字不需要加单位
实际开发中组件的样式会越来越复杂,建议使用StyleSheet.create来集中定义组件的样式。StyleSheet.create的参数是一个对象,对象中的每个属性都是以键值对的形式定义。
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View} from 'react-native';
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
android:
'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
type Props = {};
export default class App extends Component<Props> {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To get started, edit App.js</Text>
<Text style={styles.instructions}>{instructions}</Text>
</View>
);
}
}
// StyleSheet.create方式定义样式
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,
},
});
// 通过style直接在组件内定义
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 style={{width: 100, height: 100, backgroundColor: 'skyblue'}} />
<View style={{width: 150, height: 150, backgroundColor: 'steelblue'}} />
</View>
);
}
}
8.Flexbox布局
React Native 中使用 flexbox 规则来指定某个组件的子元素的布局。Flexbox 可以在不同屏幕尺寸上提供一致的布局结构。
1.宽高:组件的高度和宽度决定了其在屏幕上显示的尺寸,也就是大小
2.弹性(Flex)宽高:在组件样式中使用flex可以使其在可利用的空间中动态地扩张或收缩。一般而言我们会使用flex:1来指定某个组件扩张以撑满所有剩余的空间。如果有多个并列的子组件使用了flex:1,则这些子组件会平分父容器中剩余的空间(前提是其父容器的尺寸不为零,如果父容器既没有固定的width和height,也没有设定flex,则父容器的尺寸为零。其子组件如果使用了flex,也是无法显示的)。如果这些并列的子组件的flex值不一样,则谁的值更大,谁占据剩余空间的比例就更大(即占据剩余空间的比等于并列组件间flex值的比)
2.无单位:React Native 中的尺寸都是无单位的,表示的是与设备像素密度无关的逻辑像素点,确保了在任何不同dpi的设备上显示都不会发生变化
React Native 中的 Flexbox 的工作原理和 web 上的 CSS 不同的是:
1.flexDirection:默认值是
column
,而不是row
,而flex也只能指定一个数字值
2.alignItems:默认值是stretch
,而不是flex-start
3.flex:只能指定一个参数并且是数字,而Web CSS中可以接受多参数
4.不支持属性:align-content,flex-basis,order,flex-flow,flex-grow,flex-shrink
9.网络请求
很多移动应用都需要从远程地址中获取数据或资源。你可能需要给某个 REST API 发起 POST 请求以提交用户数据,也可能只是需要从某个服务器上获取一些静态内容。
在React Native中是使用fetch来实现网络请求的。可以参考Fetch 请求文档来查看所有可用的参数。
发起请求
要从任意地址获取内容的话,只需简单地将网址作为参数传递给 fetch 方法即可
fetch('https://mywebsite.com/mydata.json');
Fetch 还有可选的第二个参数,可以用来定制 HTTP 请求一些参数,可以指定 header 参数,或是指定使用 POST 方法,或是提交数据等等:
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
}),
});
提交数据的格式关键取决于 headers 中的Content-Type。Content-Type有很多种,对应 body 的格式也有区别。到底应该采用什么样的Content-Type取决于服务器端,所以请和服务器端的开发人员沟通确定清楚。常用的'Content-Type'除了上面的'application/json',还有传统的网页表单形式,如:
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'key1=value1&key2=value2',
});
使用 Chrome 调试目前无法查看到 React Native 中的网络请求,可以使用第三方的react-native-debugger来进行查看。
10.基础组件
View
在Web开发中,div是最重要的一个元素,是页面布局的基础。在React Native开发中,View组件的作用类似于div,是最基本的组件,被看作是容器组件,不管是显示一个文本还是输入框,都可以把它们放在View组件内部。不论在什么平台上,View 都会直接对应一个平台的原生视图,无论它是 UIView、div还是 android.view.View
Text
显示文本内容的组件
Image
显示图片内容的组件。用于显示多种不同类型图片的 React 组件,包括网络图片、静态资源、临时的本地图片、以及本地磁盘上的图片(如相册)等
TextInput
文本输入框组件
ScrollView
可滚动的容器视图。封装了平台的ScrollView(滚动视图)的组件,同时还集成了触摸锁定的“响应者”系统。
必须要有一个确定的高度,在确保父级容器已经设置了高度情况下,可以通过设置flex: 1
以使其自动填充父容器的空余空间
和
FlatList
组件相比:ScrollView
会简单粗暴地把所有子元素一次性全部渲染出来,毫无疑问这会导致一些性能问题,而FlatList
会惰性渲染子元素,只在它们将要出现在屏幕中时才开始渲染。除非你要渲染的数据特别少,否则你都应该尽量使用FlatList
,此外FlatList
还可以方便地渲染行间分隔线,支持多列布局,无限滚动加载等等
StyleSheet
提供类似CSS样式表的样式抽象层
11.交互控件
常见的跨平台的交互控件
Button
一个简单的跨平台的按钮控件。组件的样式是固定的,可以使用TouchableOpacity或是TouchableNativeFeedback组件来定制自己所需要的按钮
Picker
在iOS和Android上调用各自原生的选择器控件。
<Picker
selectedValue={this.state.language}
style={{ height: 50, width: 100 }}
onValueChange={(itemValue, itemIndex) => this.setState({language: itemValue})}>
<Picker.Item label="Java" value="java" />
<Picker.Item label="JavaScript" value="js" />
</Picker>
Slider
滑动数值选择器
Switch
开关,跨平台通用受控组件。通过onValueChange回调来更新value属性以响应用户的操作。如果不更新value属性,组件只会按一开始给定的value值来渲染且保持不变
12.列表视图
只会渲染当前屏幕可见的元素(懒加载),这样有利于显示大量的数据
FlatList
常用功能
1.完全跨平台。
2.支持水平布局模式。
3.行组件显示或隐藏时可配置回调事件。
4.支持单独的头部组件。
5.支持单独的尾部组件。
6.支持自定义行间分隔线。
7.支持下拉刷新。
8.支持上拉加载。
9.支持跳转到指定行(ScrollToIndex)
SectionList
类似FlatList,多了分组显示。
常用功能
1.完全跨平台。
2.行组件显示或隐藏时可配置回调事件。
3.支持单独的头部组件。
4.支持单独的尾部组件。
5.支持自定义行间分隔线。
6.支持分组的头部组件。
7.支持分组的分隔线。
8.支持多种数据源结构
9.支持下拉刷新。
10.支持上拉加载。