Props和State比较
props
props是properties的缩写,您可以把任意类型的数据传递给子组件,如此子组件的默认数据源就是props。
你可以在挂在组件的时候设置它的props:
let data = {name : xxx};
<
Component data = {data} /
>
在使用中可以通过this.props.data调用props属性,但是切记不能用this.props.xxx修改属性,这会导致props错乱。如:
this.props.data = {name:'nextxxxx'}
// 这是错误的示范,切记不要修改props及其子属性,可以把props当做const类型来看待。
- 设置默认值
static defaultProps = {
name:'CRN'
};
- 属性检查
static propTypes = {
name:React.PropTypes.string
};
state
它是组件的内部状态属性,主要用来存储组件自身需要的数据。 除了初始化时可能由props来决定,之后就完全由组件自身去维护。 组件中由系统定义了setState方法,每次调用setState时都会更新组件的状态,触发render方法重新渲染界面。 需要注意的是render方法是被异步调用的,这可以保证同步的多个setState方法只会触发一次render,这样做是有利于提高性能的。
- 设置默认值
constructor(props){
super(props)
this.state = {
showName:'CRN'
}
//切记,在此处不要使用setState()
}
- 刷新页面状态
componmentWillMount(){
this.setState({
showName:'RN'
})
}
提到state就不得不提组件的生命周期
组件生命周期
- 创建阶段
该阶段主要发生在创建组件类的时候,在这个阶段中会初始化组件的属性类型和默认属性
static defaultProps = {
name: ..,
}; // 注意这里有分号
static propTypes = {
name: React.PropTypes.string.isRequired,
}; // 注意这里有分号
- 实例化阶段
该阶段主要发生在组件类被调用(实例化)的时候。
1、constructor 这里是对控件的一些状态进行初始化,由于该函数不同于defaultProps
,在以后的过程中,会再次调用,所以可以将控制控件的状态的一些变量放在这里初始化.
constructor(props){
super(props)
this.state = {
showName:'CRN'
}
//切记,在此处不要使用setState()
}
2、componentWillMount()
准备加载组件。 这个调用时机是在组件创建,并初始化了状态之后,在第一次绘制 render() 之前。可以在这里做一些业务初始化操作,也可以设置组件状态。这个函数在整个生命周期中只被调用一次。 如果在这个函数里面调用setState,本次的render函数可以看到更新后的state,并且只渲染一次。
componmentWillMount(){
this.setState({
showName:'RN'
})
}
3、render()
render是一个组件必须有的方法,形式为一个函数,渲染界面,并返回JSX或其他组件来构成DOM,和Android的XML布局、WPF的XAML布局类似,只能返回一个顶级元素。
4、componentDidMount()
调用了render方法后,组件加载成功并被成功渲染出来以后所执行的hook函数,一般会将网络请求等加载数据的操作,放在这个函数里进行,来保证不会出现UI上的错误。
- 运行(更新)阶段
1、componentWillReceiveProps(nextProps)
当组件接收到新的props时,会触发该函数。在该函数中,通常可以调用setState()来完成对state的修改。 输入参数 nextProps 是即将被设置的属性,旧的属性还是可以通过 this.props 来获取。在这个回调函数里面,你可以根据属性的变化,通过调用 this.setState() 来更新你的组件状态,这里调用更新状态是安全的,并不会触发额外的 render() 调用
componentWillReceiveProps: function(nextProps) {
this.setState({
showName: nextProps.ShowName
});
}
2、shouldComponentUpdate(nextProps, nextState)
返回布尔值(决定是否需要更新组件)
输入参数 nextProps 和上面的 componentWillReceiveProps 函数一样,nextState 表示组件即将更新的状态值。这个函数的返回值决定是否需要更新组件,如果 true 表示需要更新,继续走后面的更新流程。否者,则不更新,直接进入等待状态。 默认情况下,这个函数永远返回 true 用来保证数据变化的时候 UI 能够同步更新。在大型项目中,你可以自己重载这个函数,通过检查变化前后属性和状态,来决定 UI 是否需要更新,能有效提高应用性能。
3、componentWillUpdate(nextProps, nextState)
shouldComponentUpdate返回true或者调用forceUpdate之后,就会开始准更新组件,并调用 componentWillUpdate()。 输入参数与 shouldComponentUpdate 一样,在这个回调中,可以做一些在更新界面之前要做的事情。需要特别注意的是,在这个函数里面,你就不能使用 this.setState 来修改状态。这个函数调用之后,就会把 nextProps 和 nextState 分别设置到 this.props 和 this.state 中。紧接着这个函数,就会调用 render() 来更新界面了。
4、render()
再确定需要更新组件时,调用render,根据diff算法,渲染界面,生成需要更新的虚拟DOM数据。
5、componentDidUpdate()
虚拟DOM同步到DOM中后,执行该方法,可以在这个方法中做DOM操作。 除了首次render之后调用componentDidMount,其它render结束之后都是调用componentDidUpdate。
componentWillMount、componentDidMount和componentWillUpdate、componentDidUpdate可以对应起来。区别在于,前者只有在挂载的时候会被调用;而后者在以后的每次更新渲染之后都会被调用。 ps:绝对不要在componentWillUpdate和componentDidUpdate中调用this.setState方法,否则将导致无限循环调用。
- 销毁阶段 该阶段主要发生组件销亡的时候,触发componentWillUnmount。当组件需要从DOM中移除的时候,通常需要做一些取消事件绑定,移除虚拟DOM中对应的组件数据结构,销毁一些无效的定时器等工作,都可以在这个方法中处理。
componentWillUnmount()
当组件要被从界面上移除的时候,就会调用 componentWillUnmount。 在这个函数中,可以做一些组件相关的清理工作,例如取消计时器、网络请求等。
一张图看懂组件的生命周期
生命周期调用和setState
生命周期 | 调用次数 | 能否使用setSate() |
---|---|---|
defaultProps / getDefaultProps | 1(全局调用一次) | 否 |
constructor / getInitialState | 1 | 否 |
componentWillMount | 1 | 是 |
render | >=1 | 否 |
componentDidMount | 1 | 是 |
componentWillReceiveProps | >=0 | 是 |
shouldComponentUpdate | >=0 | 否 |
componentWillUpdate | >=0 | 否 |
componentDidUpdate | >=0 | 否 |
componentWillUnmount | 1 | 否 |
动手撸个demo加强下记忆
'use strict';
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Image
} from 'react-native';
import {
Page,
Button,
ViewPort
} from '@ctrip/crn';
class Greeting extends Component {
constructor(props){
super(props)
this.state = {
name: props.name|| "Greeting",
other:'other'
}
console.log('Greeting constructor');
}
refreshState(name){
this.setState({
name:name
})
}
componentWillMount(){
console.log('componentWillMount');
}
componentDidMount(){
console.log("componentDidMount");
}
componentWillReceiveProps(nextProps){
console.log("componentWillReceiveProps nextProps = ",nextProps);
this.setState({
name:nextProps.name
})
}
shouldComponentUpdate(nextProps,nextState){
console.log("shouldComponentUpdate nextProps = ",nextProps, " nextState = ",nextState);
if(nextProps.name === "RN"){
console.log("shouldComponentUpdate return false");
return false;
}
return true;
}
componentWillUpdate(nextProps,nextState){
console.log("componentWillUpdate nextProps = ",nextProps, " nextState = ",nextState);
}
componentDidUpdate(){
console.log("componentDidUpdate");
}
render() {
console.log("Greeting render");
return (
<
Text
>
Hello {this.state.name}!
<
/Text
>
);
}
}
export default class Page1 extends Page {
constructor(props){
super(props)
this.state = {
index:0,
pics:[{uri:"http://m.vstou.com/img/201510/dm1_5.jpg"},{uri:"http://m.vstou.com/img/201510/dm2_5.jpg"}],
names:['CRN','RN']
}
}
render() {
console.log("super render");
const { pics , names , index } = this.state;
let pic = pics[index];
let name = names[index]
return (
<
ViewPort
>
<
View style={styles.container}
>
<
Greeting ref="greet" name={name}/
>
<
Button onPress={this._onPress.bind(this)} textStyle={{color:'black'}}
>
父组件setState
<
/Button
>
<
Button onPress={this._greetOnPress.bind(this)} textStyle={{color:'black'}}
>
Greeting setState
<
/Button
>
<
/View
>
<
/ViewPort
>
);
}
_onPress(){
const { index } = this.state
let next = index ? 0 : 1
console.log(" ================ 父组件setState ================");
this.setState({
index:next
})
}
//子组件改变state
_greetOnPress(){
console.log(" ================ Greeting setState ================");
this.refs.greet.refreshState("_greetOnPress")
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
image:{
width:200,
height:200
}
});
解析下:
- 当页面首次渲染 :
super render -
>
Greeting constructor -
>
componentWillMount -
>
Greeting render -
>
componentDidMount
- 点击
父组件setState
props.name='RN':
super render -
>
componentWillReceiveProps nextProps = Object {name: "RN"} -
>
shouldComponentUpdate nextProps = Object {name: "RN"} nextState = Object {name: "RN", other: "other"}
shouldComponentUpdate return false
因为shouldComponentUpdate返回false,所以后续的更新不在执行
- 点击
父组件setState
props.name='CRN':
super render -
>
componentWillReceiveProps nextProps = Object {name: "CRN"} -
>
shouldComponentUpdate nextProps = Object {name: "CRN"} nextState = Object {name: "CRN", other: "other"} -
>
componentWillUpdate nextProps = Object {name: "CRN"} nextState = Object {name: "CRN", other: "other"} -
>
Greeting render -
>
componentDidUpdate
- Greeting setState :
shouldComponentUpdate nextProps = Object {name: "CRN"} nextState = Object {name: "_greetOnPress", other: "other"} -
>
componentWillUpdate nextProps = Object {name: "CRN"} nextState = Object {name: "_greetOnPress", other: "other"} -
>
Greeting render -
>
componentDidUpdate
因为是greet组件刷新的自己的状态,所以直接进入shouldComponentUpdate判断
state的工作原理和React.js完全一致,所以对于处理state的一些更深入的细节,你可以参阅React.Component API。
接下来就要进入第二阶段了,深度了解CRNProps和State比较
props
props是properties的缩写,您可以把任意类型的数据传递给子组件,如此子组件的默认数据源就是props。
你可以在挂在组件的时候设置它的props:
let data = {name : xxx};
<
Component data = {data} /
>
在使用中可以通过this.props.data调用props属性,但是切记不能用this.props.xxx修改属性,这会导致props错乱。如:
this.props.data = {name:'nextxxxx'}
// 这是错误的示范,切记不要修改props及其子属性,可以把props当做const类型来看待。
- 设置默认值
static defaultProps = {
name:'CRN'
};
- 属性检查
static propTypes = {
name:React.PropTypes.string
};
state
它是组件的内部状态属性,主要用来存储组件自身需要的数据。 除了初始化时可能由props来决定,之后就完全由组件自身去维护。 组件中由系统定义了setState方法,每次调用setState时都会更新组件的状态,触发render方法重新渲染界面。 需要注意的是render方法是被异步调用的,这可以保证同步的多个setState方法只会触发一次render,这样做是有利于提高性能的。
- 设置默认值
constructor(props){
super(props)
this.state = {
showName:'CRN'
}
//切记,在此处不要使用setState()
}
- 刷新页面状态
componmentWillMount(){
this.setState({
showName:'RN'
})
}
提到state就不得不提组件的生命周期
组件生命周期
- 创建阶段
该阶段主要发生在创建组件类的时候,在这个阶段中会初始化组件的属性类型和默认属性
static defaultProps = {
name: ..,
}; // 注意这里有分号
static propTypes = {
name: React.PropTypes.string.isRequired,
}; // 注意这里有分号
- 实例化阶段
该阶段主要发生在组件类被调用(实例化)的时候。
1、constructor 这里是对控件的一些状态进行初始化,由于该函数不同于defaultProps
,在以后的过程中,会再次调用,所以可以将控制控件的状态的一些变量放在这里初始化.
constructor(props){
super(props)
this.state = {
showName:'CRN'
}
//切记,在此处不要使用setState()
}
2、componentWillMount()
准备加载组件。 这个调用时机是在组件创建,并初始化了状态之后,在第一次绘制 render() 之前。可以在这里做一些业务初始化操作,也可以设置组件状态。这个函数在整个生命周期中只被调用一次。 如果在这个函数里面调用setState,本次的render函数可以看到更新后的state,并且只渲染一次。
componmentWillMount(){
this.setState({
showName:'RN'
})
}
3、render()
render是一个组件必须有的方法,形式为一个函数,渲染界面,并返回JSX或其他组件来构成DOM,和Android的XML布局、WPF的XAML布局类似,只能返回一个顶级元素。
4、componentDidMount()
调用了render方法后,组件加载成功并被成功渲染出来以后所执行的hook函数,一般会将网络请求等加载数据的操作,放在这个函数里进行,来保证不会出现UI上的错误。
- 运行(更新)阶段
1、componentWillReceiveProps(nextProps)
当组件接收到新的props时,会触发该函数。在该函数中,通常可以调用setState()来完成对state的修改。 输入参数 nextProps 是即将被设置的属性,旧的属性还是可以通过 this.props 来获取。在这个回调函数里面,你可以根据属性的变化,通过调用 this.setState() 来更新你的组件状态,这里调用更新状态是安全的,并不会触发额外的 render() 调用
componentWillReceiveProps: function(nextProps) {
this.setState({
showName: nextProps.ShowName
});
}
2、shouldComponentUpdate(nextProps, nextState)
返回布尔值(决定是否需要更新组件)
输入参数 nextProps 和上面的 componentWillReceiveProps 函数一样,nextState 表示组件即将更新的状态值。这个函数的返回值决定是否需要更新组件,如果 true 表示需要更新,继续走后面的更新流程。否者,则不更新,直接进入等待状态。 默认情况下,这个函数永远返回 true 用来保证数据变化的时候 UI 能够同步更新。在大型项目中,你可以自己重载这个函数,通过检查变化前后属性和状态,来决定 UI 是否需要更新,能有效提高应用性能。
3、componentWillUpdate(nextProps, nextState)
shouldComponentUpdate返回true或者调用forceUpdate之后,就会开始准更新组件,并调用 componentWillUpdate()。 输入参数与 shouldComponentUpdate 一样,在这个回调中,可以做一些在更新界面之前要做的事情。需要特别注意的是,在这个函数里面,你就不能使用 this.setState 来修改状态。这个函数调用之后,就会把 nextProps 和 nextState 分别设置到 this.props 和 this.state 中。紧接着这个函数,就会调用 render() 来更新界面了。
4、render()
再确定需要更新组件时,调用render,根据diff算法,渲染界面,生成需要更新的虚拟DOM数据。
5、componentDidUpdate()
虚拟DOM同步到DOM中后,执行该方法,可以在这个方法中做DOM操作。 除了首次render之后调用componentDidMount,其它render结束之后都是调用componentDidUpdate。
componentWillMount、componentDidMount和componentWillUpdate、componentDidUpdate可以对应起来。区别在于,前者只有在挂载的时候会被调用;而后者在以后的每次更新渲染之后都会被调用。 ps:绝对不要在componentWillUpdate和componentDidUpdate中调用this.setState方法,否则将导致无限循环调用。
- 销毁阶段 该阶段主要发生组件销亡的时候,触发componentWillUnmount。当组件需要从DOM中移除的时候,通常需要做一些取消事件绑定,移除虚拟DOM中对应的组件数据结构,销毁一些无效的定时器等工作,都可以在这个方法中处理。
componentWillUnmount()
当组件要被从界面上移除的时候,就会调用 componentWillUnmount。 在这个函数中,可以做一些组件相关的清理工作,例如取消计时器、网络请求等。
一张图看懂组件的生命周期
生命周期调用和setState
生命周期 | 调用次数 | 能否使用setSate() |
---|---|---|
defaultProps / getDefaultProps | 1(全局调用一次) | 否 |
constructor / getInitialState | 1 | 否 |
componentWillMount | 1 | 是 |
render | >=1 | 否 |
componentDidMount | 1 | 是 |
componentWillReceiveProps | >=0 | 是 |
shouldComponentUpdate | >=0 | 否 |
componentWillUpdate | >=0 | 否 |
componentDidUpdate | >=0 | 否 |
componentWillUnmount | 1 | 否 |
动手撸个demo加强下记忆
'use strict';
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Image
} from 'react-native';
import {
Page,
Button,
ViewPort
} from '@ctrip/crn';
class Greeting extends Component {
constructor(props){
super(props)
this.state = {
name: props.name|| "Greeting",
other:'other'
}
console.log('Greeting constructor');
}
refreshState(name){
this.setState({
name:name
})
}
componentWillMount(){
console.log('componentWillMount');
}
componentDidMount(){
console.log("componentDidMount");
}
componentWillReceiveProps(nextProps){
console.log("componentWillReceiveProps nextProps = ",nextProps);
this.setState({
name:nextProps.name
})
}
shouldComponentUpdate(nextProps,nextState){
console.log("shouldComponentUpdate nextProps = ",nextProps, " nextState = ",nextState);
if(nextProps.name === "RN"){
console.log("shouldComponentUpdate return false");
return false;
}
return true;
}
componentWillUpdate(nextProps,nextState){
console.log("componentWillUpdate nextProps = ",nextProps, " nextState = ",nextState);
}
componentDidUpdate(){
console.log("componentDidUpdate");
}
render() {
console.log("Greeting render");
return (
<
Text
>
Hello {this.state.name}!
<
/Text
>
);
}
}
export default class Page1 extends Page {
constructor(props){
super(props)
this.state = {
index:0,
pics:[{uri:"http://m.vstou.com/img/201510/dm1_5.jpg"},{uri:"http://m.vstou.com/img/201510/dm2_5.jpg"}],
names:['CRN','RN']
}
}
render() {
console.log("super render");
const { pics , names , index } = this.state;
let pic = pics[index];
let name = names[index]
return (
<
ViewPort
>
<
View style={styles.container}
>
<
Greeting ref="greet" name={name}/
>
<
Button onPress={this._onPress.bind(this)} textStyle={{color:'black'}}
>
父组件setState
<
/Button
>
<
Button onPress={this._greetOnPress.bind(this)} textStyle={{color:'black'}}
>
Greeting setState
<
/Button
>
<
/View
>
<
/ViewPort
>
);
}
_onPress(){
const { index } = this.state
let next = index ? 0 : 1
console.log(" ================ 父组件setState ================");
this.setState({
index:next
})
}
//子组件改变state
_greetOnPress(){
console.log(" ================ Greeting setState ================");
this.refs.greet.refreshState("_greetOnPress")
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
image:{
width:200,
height:200
}
});
解析下:
- 当页面首次渲染 :
super render -
>
Greeting constructor -
>
componentWillMount -
>
Greeting render -
>
componentDidMount
- 点击
父组件setState
props.name='RN':
super render -
>
componentWillReceiveProps nextProps = Object {name: "RN"} -
>
shouldComponentUpdate nextProps = Object {name: "RN"} nextState = Object {name: "RN", other: "other"}
shouldComponentUpdate return false
因为shouldComponentUpdate返回false,所以后续的更新不在执行
- 点击
父组件setState
props.name='CRN':
super render -
>
componentWillReceiveProps nextProps = Object {name: "CRN"} -
>
shouldComponentUpdate nextProps = Object {name: "CRN"} nextState = Object {name: "CRN", other: "other"} -
>
componentWillUpdate nextProps = Object {name: "CRN"} nextState = Object {name: "CRN", other: "other"} -
>
Greeting render -
>
componentDidUpdate
- Greeting setState :
shouldComponentUpdate nextProps = Object {name: "CRN"} nextState = Object {name: "_greetOnPress", other: "other"} -
>
componentWillUpdate nextProps = Object {name: "CRN"} nextState = Object {name: "_greetOnPress", other: "other"} -
>
Greeting render -
>
componentDidUpdate
因为是greet组件刷新的自己的状态,所以直接进入shouldComponentUpdate判断
state的工作原理和React.js完全一致,所以对于处理state的一些更深入的细节,你可以参阅React.Component API。
接下来就要进入第二阶段了,深度了解CRN