前言
这篇文章来介绍一下RN的属性和状态,以及在之前Hello World项目中已经出现的比如style等UI样式的使用,之后我们就能使用这些来搭建一些简单的UI界面。
还记得搭建环境的时候init的AwesomeProject项目吧,我们把它导入到WebStorm中,下边的内容都可以在里边改代码!
关于如何运行,可以查看上一篇博客,这里就不赘述了!
Props(属性)
大多数组件在创建时就可以使用各种参数来进行定制。用于定制的这些参数就称为props(属性)。
我们还是来对比Android中的属性,比如TextView,常见的width
,height
,text
,padding
等等,ImageView的src
,scaleType
等,这些就是这些控件的属性。
那么同样的对于RN中的组件来说,它也有一系列与之对应的属性,只不过写法上有些不同罢了!
这里我们举个例子,以RN中的Image
,对应Android中的ImageView,Image
是用来展示图片的组件。
那我们要用Image这个组件,首先就需要导入进来:
import {
AppRegistry,
Image,
StyleSheet,
Text,
View
} from 'react-native';
我们在项目中将Image添加进来,之后就可以使用这个组件了!
我们在网上随便找来一张图片!然后将render(){}
方法中的内容改为:
let pic={
uri: 'http://p4.music.126.net/cq1STvQ6q5b_Eg5grsTjYQ==/3275445147663993.jpg'
};
//加载网络图片,必须指定图片尺寸
return (
<View style={styles.container}>
<Image source={pic} style={{width: 200, height: 200}} />
<Text style={styles.welcome}>This is a picture of Taylor Swift</Text>
</View>
);
然后我们运行一下,看一下效果!
代码中<Image source={pic} style={{width: 200, height: 200}} />
的source
就是组件Image的属性,指定要显示的图片的地址,这个属性很类似ImageView的src属性。
需要注意的一点:{pic}
外围有一层括号,我们需要用括号来把pic这个变量嵌入到JSX语句中。括号的意思是括号内部为一个js变量或表达式,需要执行后取值。因此我们可以把任意合法的JavaScript表达式通过括号嵌入到JSX语句中。
跟我们直接把地址放进去是一样的:
<Image source={{uri: 'http://p4.music.126.net/cq1STvQ6q5b_Eg5grsTjYQ==/3275445147663993.jpg'}} style={{width: 200, height: 200}} />
另外就是,Image组件在加载网络图片的时候,必须要指定宽高,这个先记着就行,关于图片我们之后再做讨论!
还有就是代码中let pic={...};
的let
是ES6新增的命令,用来声明变量。它的用法类似于var
,但是所声明的变量,只在let命令所在的代码块内有效。
前边提到的import
,class
,const
都是ES6**新增的用于声明变量的命令**,加上ES5中已经有的var
,function
,共有6种声明不同变量的命令!
样式style
这里style也是Image的属性,而且几乎全部的组件都有style这个属性,这里主要用来设置宽高,而且是直接在里边写了{width: 200, height: 200}
,但是我们还记得这个项目里边,
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,然后再去引用是一样的。
从这个层面上看,style更像是一个属性的集合,里边是一个个的属性,我们把需要设置的属性放在里边,然后一句话去引用。这跟Android里边的style是非常类似的!
关于style,这些样式名基本上是遵循了web上的CSS的命名,只是按照JS的语法要求使用了驼峰命名法,例如将background-color
改为backgroundColor
style属性可以是一个普通的JavaScript对象。这是最简单的用法,就像示例项目中那样。还可以传入一个数组——在数组中位置居后的样式对象比居前的优先级更高,这样你可以间接实现样式的继承。
比如:
<Text style={[styles.container,styles.instructions]}>
重点:后声明的属性会覆盖先声明的同名属性。
就是如果container和instructions,如果有同名的属性,那么instructions中的该属性会起作用,而container中的该属性则无效!
自定义组件的属性
我们在前一篇博客中说过,可以extents Component
来自定义组件,自定义的组件也可以使用props
,通过在不同的场景使用不同的属性定制,可以尽量提高自定义组件的复用范畴。只需在render函数中引用this.props
,然后按需处理即可。
比如说我们不是这一张图片,是好多明星的图片,那我们在描述这张图片的时候,如果还是写一个个的<Text/>
来说This is a picture of xxxx,那也太low了!所以,我们可以将下边的描述单独抽离出来成一个组件,而且将明星名字作为一个属性,就可以复用了!
自定义一个组件:
class Description extends Component{
render() {
return (
<Text style={styles.welcome}>This is a picture of {this.props.name}</Text>
);
}
}
然后这样用:
return (
<View style={styles.container}>
<Image source={pic} style={{width: 200, height: 200}} />
<Description name="Taylor Swift"/>
</View>
);
这里的name
就是我们自定义组件Description的一个属性,当然你可以用其他的词,只要用的时候写一样的就OK!
重新reload一下,发现运行效果是一样的!
this.props.children
2018/2/26更新
一般来说,我们使用this.props
来获取的属性是和父组件传入的属性是对应的,但是有一个特殊的props需要注意,那就是this.props.children
。
this.props.children
常用于包含多个数量不确定子组件的父组件,来进行遍历渲染!最常见的应用例子:app中首页用于展示内容的banner或者swiper!
所以有以下几个需要注意的点:
- 列表数量以及内容不确定,在父组件创建的时候才能确定
- 利用
this.props.children
从父组件获取需要展示的列表项内容 - 使用
React.Children.map
方法遍历children,逐项设置,此方法返回一个数组对象,数组中的元素是child
一个简单的用法示例:
<Swiper>
<View style={{backgroundColor: 'red'}}/>
<View style={{backgroundColor: 'green'}}/>
<View style={{backgroundColor: 'blue'}}/>
</Swiper>
Swiper的render方法
{
React.Children.map(this.props.children, (child) => {
return (
{child}
)
})
}
State(状态)
这里借助官网的说明:
我们使用两种数据来控制一个组件:props
和state
。props
是在父组件中指定,而且一经指定,在被指定的组件的生命周期中则不再改变。 对于需要改变的数据,我们需要使用state
。
一般来说,你需要在constructor中初始化state
(译注:这是ES6的写法,早期的很多ES5的例子使用的是getInitialState方法来初始化state,这一做法会逐渐被淘汰),然后在需要修改时调用setState
方法。
通过上面的描述,我们发现思路呢和java代码很类似啊,constructor顾名思义构造器,在构造器中给state初始化一个值,然后如果需要修改,就调用setState
方法,也很好理解!
这里给出官方例子,不过我们还在Description中写:
class Description extends Component {
constructor(props) {
super(props);
this.state = { showText: true };
// 每1000毫秒对showText状态做一次取反操作
setInterval(() => {
this.setState(previousState => {
return { showText: !previousState.showText };
});
}, 1000);
}
render() {
// 根据当前showText的值决定是否显示text内容
// 这里稍微改动一下
let text="This is a picture of " + this.props.name;
let display = this.state.showText ? text : ' ';
return (
<Text>{display}</Text>
);
}
}
reload一下,就可以看见这些字一闪一闪的了!
需要注意的地方:
setInterval
,setTimeout
等是定时器函数,这些之后会作了解!
如官网所说,我们一般不会在定时器函数(setInterval、setTimeout等)中来操作state,典型的场景是在接收到服务器返回的新数据,或者在用户输入数据之后。
同样的对比Android,这里相当于模拟网络请求数据,然后延时1s,去改变UI状态!这样是不是好理解多了!
更高端一点的,可以使用一些“状态容器”比如Redux来统一管理数据流,这个以后再去慢慢了解!
结语
本篇文章过后,我们就了解了组件的属性和状态,以及为组件设置样式style,包括自定义组件。这样我们能够基本编写出一些简单的UI界面了!
好了,先这样了,下篇再见!