props
与state
的差别是React新手最常问到的问题?它们貌似相似,但用法其实完全不同。那它们的区别是什么呢?
“props”是什么意思呢?其实就是"properties"的缩写。它有什么特点呢?
props
是被传入组件的看个React Guide里的例子
class Welcome extends React.Component {
render() {
return <h1>Hello {this.props.name}</h1>;
}
}
const element = <Welcome name="Sara" />;
你可以在CodePen上体验上面代码片的效果。
这行表示,创建的组件带有属性name,值为"Sara"
这听起来有点像函数调用哎…
没错,属性被传入组件中,就如同参数被传入一个函数。事实上,我们也可以重写上面组件:
function Welcome(props) {
return <h1>Hello {props.name}</h1>;
}
现在看更明显了:
props就如同参数一样
那么props应该是从上层(组件)传递来的吧?
经常如此,但不总是。一个组件也可包含带默认值的props,这样如果props 没有传进来,依然可以设置它的值。
上面的例子中,如果我们在Welcome
组件中,给name
属性加一个defaultProps
,这个属性就不是必填的了:
class Welcome extends React.Component {
render() {
return <h1>Hello {this.props.name}</h1>;
}
}
// 定义默认属性值
Welcome.defaultProps = {
name: "world",
};
现在,如果调用Welcome
组件且没传name属性,它就会渲染为 Hello world
props可以来自父组件,也可以被自身设置
props
的值什么?!我早就这么做了…
早期React版本提供了setProps
和replaceProps
用来改变props
的值,但这最近的版本这些方法早就被标记为deprecated
(不推荐使用)。在组件的生命周期中,props
不应该被更改。
好吧,我不会再改props了。
由于props
是被传入的,并且不能改变,你可以认为React组件只使用了“纯净”(pure)的props
。也就是,传入相同的props,渲染出的一定不会变。这使得组件很容易被测试。
除了props
,state
也包含了组件的数据。然而,数据的类型和如何操作时不同的。
一个组件默认是没有状态的,例如上面例子中的Welcome
就是无状态的
function Welcome(props) {
return <h1>Hello {props.name}</h1>;
}
那什么时候会使用状态呢?
如果一个组件需要追踪渲染时自己生成和更新的信息时,就用到了状态。
我们通过一个简单的组件,看state
随动作如何变化。假设我们有一个按钮,它可以记录我们点击的次数。代码如下:
class Button extends React.Component {
constructor() {
super();
this.state = {
count: 0,
};
}
updateCount() {
this.setState((prevState, props) => {
return { count: prevState.count + 1 }
});
}
render() {
return (<button
onClick={() => this.updateCount()}
>
Clicked {this.state.count} times
</button>);
}
}
你可以再CodePen上试一下效果。
使用state
后代码复杂了好多。不用担心我们现在分解一下上面的代码,让它更好懂。
props
和state
的第一个区别:
state
是在组件中生成的我们看下构造函数constructor
:
constructor() {
super();
this.state = {
count: 0,
};
}
在这里,state
被初始化,初始化的值可以像上面一样硬编码,也可以来自于props
的值。
等等,这好像有点让人困惑
我知道,但这其实很合理-你不能改变props
的值,但你对组件接收的数据做些加工时很合理需求,这也是需要state
的地方。
我们看下第二个区别:
state
的值是可变的看下updateCount
函数:
updateCount() {
this.setState((prevState, props) => {
return { count: prevState.count + 1 }
});
}
我们更改状态以跟踪总点击次数。这里的关键是setState
方法。首先,注意setState
方法接收一个函数作为参数,因为它可能是异步执行的。它需要一个回调函数,而不是立刻更新状态。你可以看到回调函数中,我们可以访问preState
,它包含了更改之前的状态。
但是setState
所做的不止是更新状态,React还让它自动重新渲染了当前的组件,真是爽!
setState
注意事项一不要尝试写this.state.count = this.state.count + 1
这样的语句。这种方式React不会监听状态的更新,因此组件不会自动渲染。总是使用setState
来更新状态。
setState
注意事项二可能有人这么写:
// 不要这样写
this.setState({
count: this.state.count + 1
});
尽管这样写看着没问题,也不会报错,而且你可能发现很多网上的例子也是这么写的。但是,这样写是不对的。因为这样写没有考虑到setState
是异步的,可能会导致状态数据不同步的错误。
程序的最后一段,render
方法:
render() {
return (<button
onClick={() => this.updateCount()}
>
Clicked {this.state.count} times
</button>);
}
onClick={() => this.updateCount()}
意思是当按钮被点击时会调用updateCount
方法。这里使用了ES6箭头函数
,ES5中写法是:onClick={this.updateCount.bind(this)}
。
按钮中,被渲染的文本是Clicked {this.state.count} times
,它将会显示this.state.count
的数值.
总结一下,整个过程是这样的:
1, 组件被构建,state.count
被初始化为0
this.state = {
count: 0,
};
2, 组件被渲染,此时按钮上显示的是"Click 0 times"
Clicked {this.state.count} times
3,用户点击按钮
4,updateCount
被调用,它绑定了组件的实例
onClick={() => this.updateCount()}
5,updateCount
调用setState
,后者的回调函数将原来的count状态值加1
this.setState((prevState, props) => {
return { count: prevState.count + 1 }
});
6,setState
触发当前组件调用其自身的render
函数
7,组件被再次渲染,按钮上文本变为“Clicked 1 times”
Clicked {this.state.count} times
虽然props
和state
都用来保存组件相关数据,但他们使用很不相同,应该被区分开来。
props
包含的信息又父组件设置(也可自己设置默认值)并且不应该被改变。
state
包含的是组件私有的信息,被组件产生改变,用于自身。
props是从父组件向子组件传递数据的一种方式…State只用于保留交互,也就是随时间变化的数据
-来自Facebook的React Guide
原文链接