接着上一篇
首先看下本文要实现的效果
html代码如下:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
<script src="index.js" type="text/babel"></script>
</head>
<body>
<div id="example">
<!-- This element's contents will be replaced with your component. -->
</div>
</body>
</html>
js代码如下:
- 方法1:
function tick() {
//div等模块变量需要使用const React elements are immutable.
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('example')
);
}
setInterval(tick, 1000);
以上方法是,一个tick函数,传入到setInterval函数中,由于setInterval函数接收一个functions和一个time参数,所以每个1秒,会调用tick函数,而tick函数会不断的去render也就是不断的去重新绘制element。
在react中,所有的react元素都是不可变的,所以建议使用const参数去修饰。
- 方法2
var TickDiv = React.createClass({
render: function () {
return ( <div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>);
}
});
setInterval(TickDiv.render,1000);
ReactDOM.render(
<TickDiv></TickDiv>,
document.getElementById('example')
);
以上代码原理:首先使用ReactDOM节点去绘制一次TickDiv元素,此时由于setInterval也每个1秒就调用TickDiv变量的render方法,也就变相实现了每隔1秒绘制一次TickDiv节点的效果。
- 方法3:
官方推荐使用更改状态的方法去重新绘制一个组件,代码如下:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
console.log("componentDidMount");
this.timerID = setInterval(
/**
* (x) => x + 6
相当于
function(x){
return x + 6;
}
*/
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
componentDidUpdate(){
console.log("componentDidUpdate......");
}
render() {
console.log("render...");
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
function App() {
return (
<div>
<Clock />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('example')
);
分析下上面的代码:此代码的写法class Clock extends React.Component {}
和var Clock=React.createClass({})
效果是一样的,一个是es6语法一个是react官方jxs的语法。(我们使用jsx来将代码封装成React组件,然后像插入普通 HTML 标签一样,在其他地方插入这个组件。使用React.createClass用于生成一个组件。)
首先在构造函constructor中,调用了父类的super(props);
也就是继承了父类的属性。从而可以通过
<App parent={'aaaaaa'}/>
将一个属性parent传入到App组件中,从而可以使用this.props.parent来获得传入的值(aaaaaa)。
this.state = {date: new Date()};
相当于调用了getInitialState方法并且实例化了一个初始状态,效果等同于
getInitialState: function() {
return {date: new Date()};
},
componentDidMount函数和componentWillUnmount函数分别做了:
- componentDidMount:设置了一个定时器,并将其保存到this对象的变量中,以便后面清理该定时器。
- componentWillUnmount:负责清理定时器
运行效果如下:
js渲染流程:
ReactDOM.render首先渲染了App组件将其放到example中。
第一次渲染结束后,调用了componentDidMount方法。此方法只会每个组件调用一次。该方法中设置了一个定时器并每隔一秒调用tick方法,tick方法用来改变组件状态。由于react会在组件状态改变的时候重新渲染组件(也有不渲染的情况后面文章继续讲)调用render方法,所以可以看到render方法会不停的被调用。componentDidUpdate方法是在组件的运行阶段,所以也会不停的被调用。
辣么大家是不是有个疑问,componentWillUnmount方法何时会被调用呢?如果直接remove掉这个组件比如:在最外层的div绑定个点击事件,点击后remove,页面会怎么显示?
关键代码如下:
<div onClick={this.removeAll}>
removeAll(e){
e.target.remove();
},
效果如下:
可以看到,在手动点击div后,确实是去掉了Helloworld和It is 下午 *,但是控制台还是在显示,说明这种方法虽然去掉了页面上的dom但是react生命周期管理的dom节点却仍然存在。
安装一款react的dom节点查看工具来查看
Chrome extension
Firefox extension
安装完成之后,查看清除后的dom节点,react插件查看效果
浏览器查看效果
也就是说,用react插件查看的dom节点还是存在的,但是用浏览器查看元素查看到的dom节点就不存在了。
所以,要想删除一个dom节点,必须在react的生命周期的管理下来删除。
代码如下:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
console.log("componentDidMount");
this.timerID = setInterval(
/**
* (x) => x + 6
相当于
function(x){
return x + 6;
}
*/
() => this.tick(),
1000
);
}
componentWillUnmount() {
console.log("componentWillUnmount*********");
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
this.props.changeParenState();
}
componentDidUpdate(){
console.log("componentDidUpdate......");
}
render() {
console.log("render...");
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
var ClockParent = React.createClass({
getInitialState: function() {
return {count: 1};
},
changeParenState:function(){
this.setState({count:2});
},
render:function(){
console.log("parent render");
return <div>
{this.state.count ==1 ?<Clock count={this.state.count} changeParenState={this.changeParenState}/>:""}
</div>
}
})
//function App() {
// return (
// <div>
// <Clock />
// </div>
// );
//}
ReactDOM.render(
<ClockParent />,
document.getElementById('example')
);
以上代码运行流程:
- ReactDOM.render触发后,ClockParent组件的生命周期方法一次运行,首先调用getInitialState方法,赋值this.state.count为1。
- 然后调用parenRender方法,其中,返回一个组件的时候做了一个判断,如果当前状态中的count变量是1就返回Clock组件否则返回一个空组件。第一次渲染的时候count为1所以返回Clock组件,也就是说开始渲染Clock。
- Clock组件和之前讲的差不多,唯一的区别就是在tick()函数中调用了父类的方法,这个叫做“状态提升”,后续文章会讲到。这里只需要知道子组件可以调用了父组件的方法并且可以讲子组件的状态传递给伏组件。
- 调用child的render方法。
- 调用child的componentDidMount方法设置定时器。
- 在定时器的作用下,改变child的state从而使得child再次调用render方法。
- 调用child的componentDidUpdate方法。
- child的运行时方法调用完毕后会通过状态提升调用父类的changeParenState方法,这个方法改变了父类的state从而会调用父类的render方法。
- 调用父类的render方法时按道理也会调用子类的render方法,但是此时,count的值为2,Clock就没有添加到父组件中,也就是变相的删除了子组件。子组件被删除后,会调用子组件的componentWillUnmount方法。
- 子组件的生命周期结束后,接着走父组件的生命周期,父组件的运行时render方法已经调用完毕,最后就剩一个componentDidUpdate方法调用下。
最后的效果图如下:
到此,本文就讲解了如何通过react生命周期删除元素、生命周期的理解、react创建简单定时器和组件的创建方式等知识点。
请尊重作者原创,不经允许不得转载,转载请标明出处,谢谢。