我们已经会将props作为初始值传给react组件。但是接下来会发生什么呢?如果用户点击了一个按钮或者输入一些文字,需要更新这些props么?
React的解决方案为state。State和props工作起来很像。区别是props是只读的,任何一个组件都可以改变自己的state甚至其他组件的状态,如果需要的话。
你需要明白重要的一点是state不是必须要有的,如果可能的话,尽量避免对组件添加状态。如果你的组件不包含state,它被成为无状态组件,当它被传入相同的props时会做同样的事情。无状态组件更容易被理解和测试,这始终是件好事。
不过总要在一些场合使用state。我们来试一波。现在我们每次输出新的名姓名和地点就要重新渲染组件。但我们可以修改class来只让页面加载一次,每次更新改变组件状态。
为了做到这个我们引入constructor()
,super()
和 this.state
.
constructor()
方法在组件实例被创建时调用,用来进行组件初始状态的设置。这个方法只会被调用一次,并且不能被直接调用。
Super()
方法有些特殊,用来表示“调用被继承组件的同名方法”。如果你还记得,Detail组件是由react.componet继承得到。这是下面这行代码的意思:
class Detail extends React.Component {
这意味着我们的Detail组件的方法继承自父类,也就是React.componet。
最后,this.state在默认情况下是未定义的,不过你可以创建它来包含任何es6允许的数据。
把这三行放在一起。1.一个Detail组件的构造函数。2.调用了react.componet的构造函数,所以react.componet能初始化。3.设定this.state来包含随机生成的一个名称和一个国家。
下面给出完整代码,放在buttonClicked()方法的上面:
src/pages/Detail.js
constructor(props) {
super(props);
this.state = {
name: chance.first(),
country: chance.country({ full: true })
};
}
我偷偷加了一点东西,是给constructer()传入一个props参数,然后传递给super(),让父类也可以用这些参数初始化。
所以,现在我们建立了state来存储随机姓名和国家,然后更改render方法来使用它:
src/pages/Detail.js
render() {
return (<div>
<p>Hello, {this.state.name}.</p>
<p>You're from {this.state.country}.</p>
<button onClick={this.buttonClicked.bind(this)}>Meet Someone New</button>
</div>);
}
由此产生的页面可能和上次没什么区别,当你点击按钮的时候,你会发现文字并没有更新,即使代码工作正常。因为姓名和国家在组件加载时已经定了,所以不管forceUpdate()多少次,输出并不会变化。
网友评论