说明:本系列所有demo代码的github地址为:https://github.com/Brucewu998/react.js-learning,笔者会不断更新这些代码,本篇代码在目录下demo-05文件夹下。
在React学习之组件与props这一节中,讲述了React相关的传值机制props,我们知道React对props由严格的保护机制,一旦给定值,在组件中是不允许改变的;在很多场合中,组件的内容需要根据数据的刷新而刷新,这个时候就可以用到React提供的State,在这里称之为状态机,State与props都是React的私有的,但不同的是,State是完全受控于组件的,所定义的属性值可以根据需求而改变,并在虚拟DOM上同步更新。在React中,state的创建方式为:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { // 状态机
value: "Hello"
}
}
}
由上面代码可知,利用ES6的class继承方法super,可以将props传递到React.Component的构造函数中。
这里我们以一个更详细的例子来看React的state(状态机)和生命周期:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = { // 状态机
date: new Date()
}
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
)
}
tick() {
this.setState({ // setState用于更新组件的state
date: new Date()
});
}
componentWillUnmount() {
clearInterval(this.timerID);
}
render() {
return (
<div>
<h1>现在的时间:</h1>
<h2 className="h2">{ this.state.date.toLocaleTimeString() }</h2>
</div>
)
}
}
上面的代码,创建了一个计时器组件,在这个计时器组件中,包含了两个方法,componentDidMount和componentWillUnmount,这两个方法称之为生命周期方法,当Clock组件第一次被渲染到DOM中的时候,设置一个计时器,用于不断地更新状态机中的date值,这个阶段在React中称之为挂载(mount),同时,当组件被销毁时,应该释放占用的相应资源,这个时候,componentWillUnmount方法就可以用于清除计时器,这在React中称之为卸载(unmount),将相应占用的资源释放掉。关于组件的生命周期相关可以参考:https://zh-hans.reactjs.org/docs/react-component.html#the-component-lifecycle。
上面的代码还实现了一个tick的方法,用于更新date这个值;我们可以注意到,这里用了setState这个方法,这是从React.Component中继承而来的一个用于更新状态机(state)中的值的方法,这个方法一般有两种应用的情况:
this.setState({
date: new Date() //直接更新
});
另外一种是需要给setState传一个回调函数来更新值,这个回调函数将整个状态机state作为参数:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {
date: new Date(),
show: true,
text: "隐藏"
}
this.handleClickShow = this.handleClickShow.bind(this);
}
handleClickShow(){
this.setState(state => ({
show: !state.show,
text: !state.show ? "隐藏" : "显示"
}))
}
}
那么为什么要用回调函数呢?因为在鼠标或者键盘监听事件中,会存在作用域的问题,往往使得this不是指向当前的组件类,所以在构建该组件类时,如果又涉及到相应监听代码,应该进行这个操作:this.handleClickShow = this.handleClickShow.bind(this),
以保证在这个方法内可以正确的访问到this。
这个demo的完整代码如下,也可以去github中查看代码:demo-05.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="../build/react.dev.js"></script>
<script src="../build/react-dom.dev.js"></script>
<script src="../build/brower.min.js"></script>
<title>Demo-07</title>
</head>
<body>
<div id="demo-7"></div>
<script type="text/babel">
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = { // 状态机
date: new Date(),
show: true,
text: "隐藏"
}
this.handleClickShow = this.handleClickShow.bind(this);
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
)
}
tick() {
this.setState({ // setState用于更新组件的state
date: new Date()
});
}
handleClickShow() {
this.setState(state => ({
show: !state.show,
text: !state.show ? "隐藏" : "显示"
}))
}
componentWillUnmount() {
clearInterval(this.timerID);
}
render() {
let isShow = this.state.show;
let element;
if (isShow) {
element = <h2 className="h2">{ this.state.date.toLocaleTimeString() }</h2>
} else {
element = null;
}
return (
<div>
<button onClick={this.handleClickShow}>{this.state.text}计时器</button>
{element}
</div>
)
}
}
ReactDOM.render(
<Clock />,
document.getElementById("demo-7")
)
</script>
</body>
</html>
<style>
.h2 {
color: blue;
}
</style>
上面的demo中,涉及到了条件渲染的知识,这个后边会做详细的讲解。
效果:
上一篇: React学习之获取真实DOM节点
下一篇:React学习之事件处理