一个ReactNative的APP界面其实是各种组件的组合,但是官方给我们提供的组件或许在样式或功能上不能满足实际的需求,所以在开发过程中,我们不可避免的需要写一些新的组件以满足项目需求。那么,它的自定义组件会有什么类型区别呢?例如说,这个组件的主要作用是“部件(widget)”还是“布局(layout)”。本人从ReactNative自定义组件上的思考多数来自于安卓的自定义控件思想。
以安卓的自定义控件为例,安卓上的自定义控件主要是继承View或ViewGroup来具体实现,前者的作用主要是提供部件(widget)的功能,后者主要是提供布局(layout)的功能。再举个例子,我们可能需要针对具体样式去实现一个标题栏,这个标题栏不需要作为容器去承载其它的控件,它仅仅只是一个最基本的标题view,所以它主要是提供部件(widget)的功能。
而ReactNative中的自定义组件,假设从功能属性大致也可以区分为widget和layout,那么我们在编写组件的时候,主要的区别即是在于this.props.children。当然,React的核心思想还是component组件,这个分类仅在于我的理解。如果不了解this.props.children,可以去看我的这篇props详解。
一个ReactNative自定义组件基本流程如下:
以一个标题组件为例,它主要功能是部件(widget),所以我们不需要去定义this.props.children。
模拟器使用安卓。
import React from 'react';
import { View, StatusBar, Image, Text, TouchableOpacity, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
export default class Title extends React.Component {
static propTypes = {
title: PropTypes.string,
onBackPress: PropTypes.func,
onMenuPress: PropTypes.func
}
// 定义属性字段的默认值
static defaultProps = {
title: '',
onBackPress: undefined,
onMenuPress: undefined
}
constructor(props) {
super(props);
// 左边:创建了this.backPress变量。右边:创建一个与backPress()相同的函数,它将绑定到这个组件,然后赋值给this.backPress变量
this.backPress = this.backPress.bind(this);
this.menuPress = this.menuPress.bind(this);
}
backPress() {
if(this.props.onBackPress) {
// 判断属性onBackPress是否传入函数,传了就执行它
this.props.onBackPress();
}
}
menuPress() {
if(this.props.onMenuPress) {
this.props.onMenuPress();
}
}
render() {
return(
<View style={styles.container}>
<StatusBar backgroundColor="#008577" barStyle="light-content"/>
<TouchableOpacity style={styles.back}
onPress={this.backPress}>
<Image source={require('../../static/images/back.png')}
style={{marginStart: 12}}/>
</TouchableOpacity>
<Text style={styles.title}>{this.props.title}</Text>
<TouchableOpacity style={styles.menu}
onPress={this.menuPress}>
<Image source={require('../../static/images/menu.png')}
style={{marginEnd: 12}}/>
</TouchableOpacity>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#008577',
height: 50
},
back: {
justifyContent: 'center',
alignItems: 'flex-start',
height: 50,
width: 50
},
title: {
flexGrow: 1,
textAlign: 'center',
color: '#ffffff',
fontSize: 18
},
menu: {
justifyContent: 'center',
alignItems: 'flex-end',
height: 50,
width: 50
}
})
具体解释请看注释。在其它组件中对于该组件的调用:
<Title title="标题"
onBackPress={()=>{
ToastAndroid.show('back', ToastAndroid.SHORT);
}}
onMenuPress={()=>{
ToastAndroid.show('menu', ToastAndroid.SHORT);
}}/>
演示:
前一个例子不需要去定义this.props.children,而LinearLayout组件是模仿安卓原生平台的LinearLayout,它的主要功能是布局layout,所以这是它们两者之间最大的区别。这里的LinearLayout组件当然没有安卓原生那么完备,仅简单示例。
import React, { Component } from 'react';
import { View, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
export default class LinearLayout extends Component {
static propTypes = {
orientation: PropTypes.string,
gravity: PropTypes.string,
}
static defaultProps = {
orientation: 'vertical',
gravity: undefined,
}
render() {
return(
<View style={{
flexDirection: (this.props.orientation === 'horizontal') ? 'row' : 'column'
}}>
{this.props.children}
</View>
)
}
}
其它组件对于该组件的调用:
import React, { Component } from 'react';
import { View, ToastAndroid, Button, Text } from 'react-native';
import Title from './Title';
import LinearLayout from './LinearLayout';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
orientation: 'vertical'
}
}
render() {
return (
<View style={{ flexDirection: 'column', flex: 1 }}>
<Title
title='标题'
onBackPress={() => {
ToastAndroid.show('back', ToastAndroid.SHORT);
}}
onMenuPress={() => {
ToastAndroid.show('menu', ToastAndroid.SHORT);
}} />
<Button title='切换' onPress={() => {
if (this.state.orientation === 'vertical') {
this.setState({
orientation: 'horizontal'
})
} else {
this.setState({
orientation: 'vertical'
})
}
}} />
<LinearLayout orientation={this.state.orientation}>
<Text>1</Text>
<Text>2</Text>
<Text>3</Text>
</LinearLayout>
</View>
);
}
}
演示:
渲染优化在这里主要还是针对组件树的渲染,我们可以有两种办法来实现,二选一:1. 继承PureComponent实现组件;2. 实现shouldComponentUpdate()方法。不了解看以看我的这两篇:Component与PureComponent的区别/ shouldComponentUpdate机制。
更多的请查看这里ReactNative性能优化总结。