接着上一篇
首先看下本文要實現的效果
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創建簡單定時器和組件的創建方式等知識點。
請尊重作者原創,不經允許不得轉載,轉載請標明出處,謝謝。