应用程序必须运用在一个“活”的情景中,由于组件是程序的基本组成单位,它必须得主动应对不断变化的场景。它必须能够和用户互动,对用户的输入做出响应。所以我们需要一种能够给组件注入“生命”的机制,让组件灵活应对具体场景中的不同变化,由此我们需要一种除了属性之外的数据存储机制,这种机制能够使得所存储的数据根据需要不断变化,同时 ,一旦数据变化后,组件根据数据的变动做相应的反应,便把反应 呈现到界面,这种机制,它有一个专有名词叫 组件的状态。
组件的状态和属性,两者之间运用机制类似,但又有一些不好察觉的区别,掌握组件状态机制的最好办法,还是通过编码事件,做一遍,很多难以言状的东西就会清楚很多。
我们要做的是一个显示控件,(调出运行的程序界面)。这个控件的功能是统计地球被雷击的次数,据统计,地球每秒被雷击100次。
组件里面有一个计数器,每过一秒它的数值就增加100,先完成基本框架,然后添加两个简单的 组件对象,例:
<!DOCTYPE html>
<html charset="utf-8">
<head>
<title>Component State!</title>
<script src="react.js"></script>
<script src="react-dom.js"></script>
<script src="browser.min.js"></script>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
var destination = document.querySelector("#container");
var LightningCounter = React.createClass({
render: function() {
return (
<h1>你好!</h1>
);
}
});
var LightningCounterDisplay = React.createClass({
render: function() {
var divStyle = {
width: 250,
textAlign: "center",
backgroundColor: "black",
padding: 40,
fontFamily: "sans-serif",
color: "#999",
borderRadius: 10
};
return (
<div style={divStyle}>
<LightningCounter/>
</div>
);
}
});
ReactDOM.render(
<LightningCounterDisplay/>
,
destination
);
</script>
</body>
</html>
首先构建了一个组件叫LightningCounterDisplay, 它的作用是绘制黑色的圆⻆矩形,在它的render函数中,把它的各种界面显示属性集中到一个json对象叫divStyle, 在该组件中,它又调用一个子组件叫LightningCounter, 它的作用是在界面上显示 相关信息。再更改这个组件的功能,让它显示更丰富的信息。通过调用React 框架的API ,把组件LightningCounterDisplay加载 在id为container的节点之下,接下来要完善计数组件的统计逻辑,也就是每秒为计数增加100, 因此我们使用原生api,setInterval来现实。
React 组件的几个接⼝:
getInitialiState 这个接⼝会在组件被浏览器加载前调用,它类似于面向对象编程中的类的初始化函数,在这里是进行数据初始化的好时机。
componentDidMount - 这个接⼝是组件被浏览器加载后所调用,在 这里你可以修改组件内置的state对象。
setState - 这个接⼝用来修改组件内置的state对象的数据
设置初始变量我们需要一个变量,用于计数闪电击打地球的次数,这个变量我们命名为strikes; 这个变量将作为组件状态对象state的一部分,在getInitialState接⼝被调用时,就得初始化它。
例:
var LightningCounter = React.createClass({
getInitialState:function() {
return {
strikes: 0
};
},
render:function() {
return (
<h1>{this.state.strikes}</h1>
);
}
});
getInitalState这个接⼝是在组件被加载时,由React 框架调用的,它返回一个json对象,对象里面含有一个变量叫 strike, 并且它的值被初始化为0. 这个对象会被组件作为内置的 state 对象保存起来。在render函数中,我们通过this.state.strikes 来访问寄存在state对象里面的strike变量。上面的代码运行后,加载进浏览器 我们可以看到strike的值显示在界面上,由于它被初始化为0,所以我们看到一个数字0在页面里显示出来
启动时钟和修改state对象
接下来我们要启动一个时钟,然后根据时钟变化来修改state对象 中strike变量的值。前面提到过,依赖setInterval调用来启动一个时钟,时钟每过一秒,就把strikes的值增加100 .当组件被浏览器加载后,立马启动时钟。代码如下:
var LightningCounter = React.createClass({
getInitialState:function() {
return {
strikes: 0
};
},
timerTick:function() {
this.setState({
strikes:this.state.strikes + 100
});
},
componentDidMount: function() {
setInterval(this.timerTick, 1000);
},
render:function() {
return (
<h1>{this.state.strikes}</h1>
);
}
});
在setInterval中传入了一个回调函数叫timerTick,这个函数是定义在组件中的,它的逻辑简单,就是通过调用React API setState 来更改组件的state对象里面的内容。setState 接收参数是一个json对象,它会把这个对象里面的内容,融合到组件的state对象里面,在这里,传入的对象中有一个属性叫 strikes,他的值是state对象里面strikes的值加上100,setState 调用后,会把该对象里面的strikes变量传递到state对象里面, 这样state对象里面的strikes变量的值就会增加100.
此时把完成的代码再次加载到浏览器中,组件中的数字随着时间的变化,不断的增加
页面上显示的数字会自动更新,这里只是更新了组件的state对象里面的内容,但这却导致页面显示的信息自动刷新了。页面的自动刷新是React 框架实现的, 只要在代码中调用了setState函数,并且更新了state对象里面的内容,React 框架会自动调用组件的render函数,如果组件包含子组件的话,那么字组件的render函数会依次调用。进而导致 的结果是,页面显示发生了一系列自动更新。让上层界面和底层数据保存同步。是应用开发的一大难题,React 框架很好的帮我们处理了这些麻烦。
结论:
对组件状态机制的研究目前了解的只能算是皮毛,真正有用的是,把组件的状态机制与用户输入相应结合起来。
未完待续