组件的state状态
初识state
state的作用
对React来说,处理接收外部props,内部也有不同的状态。
state状态的作用是管理当前组件的内部数据,让React组件可以随用户操作、网络响应或者其他变化而动态更改输出内容
为class组件添加state
React规定:组件的内部状态记录在组件的this.state对象上面
- 方法一:为组件添加
constructor构造函数,然后在该函数中为this.state赋初始值
class App extends React.Component {
constructor(){
super();
this.state = { count: 0}
}
render(){
return <button>你点了我 {this.state.count} 次</button>
} }
- 方法二:使用class属性新提案
class App extends React.Component {
state = { count: 0 }
render(){
return <button>你点了我 {this.state.count} 次</button>
} }
将props的数据挂载到state
之前说过,React组件是不能修改props属性的,但是可以把props挂载到state对象上,将其视为组件所需管理的数据之一,如:
class Counter extends React.Component {
constructor(props){
super(props);
this.state = {
// 若 props 未传入 count,则赋初始值为 0
count: this.props.count || 0
}
}
render(){
return <button>你点了我 {this.state.count} 次</button>
} }
若需要在constructor函数函数中访问this.props,则使用props参数来调用父类的构造函数是必须的,否则会出现this.props为undefined的Bug
更新state、更新组件
setState API
更新组件state的唯一方式是调用组件实例的setState()方法。
setState(Object || Function [, callback])
API解析:
-
作用:将第一个参数返回的对象与组件当前的状态对象(
this.state)进行浅层合并,并通知React使用更新后的state重新渲染此组件. -
参数:
1、第一个参数可以说Function类型或Object类型。
// Function 类型可接收两个形参:state 与 props,分别表示组件当前的 state 与 props setState((state, props) => {})2、callback为可选的回调函数,它将在state完成对象合并、并重新渲染组件后执行
组件更新
使用setState()更新组件视图:
class Counter extends React.Component {
constructor(props){
super(props);
this.state = {
count: this.props.count || 0
}
}
handleClick = () => {
let {count} = this.state;
this.setState({count: ++count})
}
render(){
return
<button onClick={this.handleClick}>你点了我 {this.state.count} 次</button>
} }
执行流程:
- 触发
handleClick函数,计算count值并调用setState方法 - 将
{count:++count}的返回值与组件当前的状态对象(this.state)进行浅合并 - 触发组件的
render函数,对比状态更新前后的虚拟DOM,在需要更新的地方更新视图
state的私有性
state状态即组件数据,它是私有的,完全由当前组件来控制 比如复用上面的Counter组件:
class App extends React.Component {
render() {
return (
<div>
<Counter />
<Counter count={0} />
<Counter count={17} />
</div>
)
} }
当点击按钮后,每个组件都各自维护自己的state,每个按钮的点击次数不会彼此受到影响。
state的三个注意点
不要直接修改state
React规定:class组件的constructor构造函数是唯一可以给this.state赋值的地方
应该是使用setState进行赋值
state的更新会被合并
当你调用setState的时候,React会把你提供的对象合并到当前的state,意味者你可以单独更新state的某个变量。 例子:
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
}; }
然后分别调用setState来单独地更新它们
queryData() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
state的更新是异步的
React出于性能考虑,会把多个setState()调用合并成一个调用,这意味着调用setState()时this.state和this.props并不会被立即更新.
例如:
handleClick = () => {
let { count } = this.state;
this.setState({ count: count })
}
由于更新是异步的,无法保证每次事件触发都能获取更新后的值,有可能会返回旧的state。 为了解决这个问题,可以让setState接收一个函数而不是一个对象,这个函数可以用上一个state作为第一个参数,将此次更新被应用时的props作为第二个参数:
handleClick = () => {
this.setState((state, props) => {
return { count: state.count + 1 }
})
}
props与state的对比
相同:
- 都是普通的js对象
- 都是用来保存组件信息的
- props与state所保存的信息都可控制组件的渲染输出
不同点:
- props是外部传递给组件的
- state是组件内部由组件自己管理的,类似于在一个函数内声明的变量
有状态组件与无状态组件
有状态组件:
function Welcome (props) { return <h1>{ props.name }~ 你好呀!</h1> }
有状态组件:
class Welcome extends React.Component {
state = { name : "Alan" }
render(){
return <div>Hello,{this.state.name}</div>
} }
注:16.8版本之后,提出了新的Hook,可以在不编写class的情况下使用state以及他的React特性