版權(quán)聲明:本文為博主原創(chuàng)文章偿枕,未經(jīng)博主允許不得轉(zhuǎn)載颅湘。
PS:轉(zhuǎn)載請注明出處
作者:TigerChain
地址:http://www.reibang.com/p/e3d1ecfb6312
本文出自TigerChain簡書
git 地址:https://github.com/tigerchain/react-lesson
教程簡介
- 1话侧、閱讀對象
本篇教程適合初學(xué)者,老鳥直接略過闯参,如果有誤,歡迎指出悲立,謝謝鹿寨。
-
2、教程難度
初級
3薪夕、Demo 地址
https://github.com/tigerchain/react-lesson/tree/master/lesson02/11-lifecycle脚草,如果大家喜歡,麻煩點個 star
正文
1原献、什么是生命周期
生命周期指的是一個對象的生老病死馏慨。當(dāng)然生命周期又為廣義和狹義的。具體分為以下幾類姑隅。
- 1写隶、動物的生命周期:從初生到死亡。
- 2讲仰、產(chǎn)品的生命周期:從開始到淘汰慕趴。(一般指提市場壽命)
- 3、語言或平臺中某個組件的生命周期:比如 activity 的生命周期鄙陡,指的就是 activity 的創(chuàng)建到銷毀的過程冕房。
- 4、其它生命周周期
2趁矾、React 的生命周期
先看 React 的生命周期圖耙册,雖然你可能不理解,通過后面的學(xué)習(xí)再回頭來看這幅圖毫捣,就會恍然大悟详拙。
一、這里說的 React 的生命周期指的就是 React 組件的生命周期培漏。React Component 通過定義幾個函數(shù)來控制組件在生命周期每個階段的功能溪厘。
總的來說 React 組件的生命周期有三種狀態(tài)
1、mounting: 插入真實 DOM </br>
2牌柄、updating: 正在被重新渲染 props 或 state 改變 </br>
3畸悬、unmounting: 卸載 移除真實 DOM
在 React 中為每個狀態(tài)又分別提供了兩種處理函數(shù),就是 will 和 did , will 是進入狀態(tài)之前調(diào)用的, did 是進入狀態(tài)之后調(diào)用的.
總的來說蹋宦,三種狀態(tài)對應(yīng)不同的函數(shù)
- mounting 對應(yīng)的函數(shù)
constructor()
componentWillMount()
render()
componentDidMount()
- updating 對應(yīng)的函數(shù)
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()
- unmounting 對應(yīng)的函數(shù)
componentWillUnmount()
PS:一個組件中 redner() 方法是必須的披粟。
二、和組件生命周期相關(guān)的函數(shù)有
上面籠統(tǒng)的說了一下和組件生命周期相關(guān)的方法冷冗,我們下面逐一來說明守屉。
- 1、構(gòu)造函數(shù)
constructor(props, context)
構(gòu)造函數(shù),在組件創(chuàng)建的時候調(diào)用一次蒿辙。
- 2拇泛、componentWillMount()
void componentWillMount()
在組件掛載之前( render()之前 )調(diào)用∷脊啵可以用于加載 Loading 條了等操作俺叭。
- 3、render
render() ;
render 方法顧名思義泰偿,就是渲染的意思熄守,它有一個返回值,就是返回一個 React 元素(自定義組件或是呈現(xiàn) DOM 組件的元素)耗跛,當(dāng)然如果你什么也不想返回就可以 return null 或 return false (組件就不顯示了)裕照,render() 里面應(yīng)該是純凈的 (不能在里面修改組件的狀態(tài),也不能在里面請求服務(wù)器等耗時操作[ componentDidMount 方法中進行耗時操作])调塌,只是用來渲染組件晋南。
- 4、componentDidMount()
void componentDidMount()
在組件掛載之后調(diào)用烟阐“峥。可以用于耗時操作(請求服務(wù)器或定時器等)。
- 5蜒茄、componentWillReceiveProps()
void componentWillReceiveProps(nextProps)
這里的 props 是父組件傳遞給子組件的唉擂。父組件發(fā)生 render 的時候就會調(diào)用子組件的 componentWillReceiveProps (不管 props 有沒有更新,也不管父子組件之間有無數(shù)據(jù)交換),在這個回調(diào)函數(shù)里面檀葛,你可以根據(jù)屬性的變化玩祟,通過調(diào)用this.setState()來更新你的組件狀態(tài),舊的屬性還是可以通過this.props來獲取,這里調(diào)用更新狀態(tài)是安全的屿聋,并不會觸發(fā)額外的render調(diào)用空扎。
- 6、shouldComponentUpdate()
bool shouldComponentUpdate(nextProps, nextState)
這個方法在組件掛載之后润讥,當(dāng)你調(diào)用 setState() 方法的時候都會調(diào)用此方法用來判斷是否要重新渲染組件转锈,如果返回 true 則需要重新渲染,如果是 false 則不會楚殿。我們可以在這個方法中處理只是數(shù)據(jù)改變撮慨,界面不改變的情況,用來優(yōu)化渲染效率。
- 7砌溺、componentWillUpdate()
void componentWillUpdate(nextProps, nextState)
顧名思義影涉,就是組件更新前被調(diào)用的方法,具體是當(dāng) props 和 state 發(fā)生改變的時候就會執(zhí)行此方法并且在 redner() 方法之前進行规伐。這個方法也在 shouldComponentUpdate() 方法返回 true 的時候就會調(diào)用蟹倾,返回 false 不會調(diào)用, 使用此方法為更新前做一些準備。初始化渲染的時候不會調(diào)用這個方法猖闪。
PS:注意一點鲜棠,在這個方法中不能會用 this.setState() 方法來修改狀態(tài)。當(dāng)這個函數(shù)調(diào)用之后培慌,就會把 nextProps 和 nextState 分別設(shè)置到 this.props 和 this.nextState 方法中岔留,接著就會調(diào)用 render() 方法來渲染了。
- 8检柬、componentDidUpdate()
void componentDidUpdate()
組件渲染后就會調(diào)用 componentDidUpdate() 方法,但是首次 render() 的時候是不會調(diào)用的竖配,首次 render() 的時候調(diào)用的是 componentDidMount() 方法何址。
componentWillMount()、componentDidMount 和 componentWillUpdate()进胯、componentDidUpdate 是一一對應(yīng)的用爪,前者是在掛載的時候會被調(diào)用,但是后者是每次更新渲染之后都會調(diào)用胁镐。
- 9偎血、componentWillUnmount()
void componentWillUnmount()
組件被卸載的時候調(diào)用,一般情況下在 componentWillUnmount() 說法中清除注冊的事件盯漂,比如取消定時器颇玷,網(wǎng)絡(luò)請求等。
3就缆、React 中的更新方式
總的來說帖渠,在 React 中,想要 redner 有以下四種方式竭宰。
假使 shouldComponentUpdate 都是返回 true 的情況下
- 1空郊、首次初化 render
- 2、調(diào)用 this.setState() 方法 (我們知道它是異步的切揭,不是每調(diào)用一次 setState 都會觸發(fā)一次 render ,React 有時可能會合并操作狞甚,再一次進行 render)
- 3、props 發(fā)生改變廓旬,但是一般不建議直接調(diào)用 this.setProps()
- 4哼审、手動調(diào)用 this.forceUpdate(不推薦這樣使用)
到目前為止,我們大體對 React 組件的生命周期有一個了解了,下面我們通過 Demo 來直觀的感覺一下棺蛛。
4怔蚌、實例演示組件的生命周期
經(jīng)過上面的學(xué)習(xí),我們大體對 React 組件的生命周期有了一定的認識旁赊,下面我們寫一個 Demo 來驗證一下桦踊。
我們可以使用前面學(xué)過的知識使用 yarn + webpack + ES6 來創(chuàng)建項目,如果不懂這些知識终畅,可以看看前面相關(guān)的章節(jié)籍胯。以下 Demo 是在 mac 環(huán)境下開發(fā)的。
1离福、打開命令行杖狼,新建 lifecycle 目錄
mkdir lifecycle
2、進入到 lifecycle 文件夾下妖爷,并新建 public 和 app 目錄蝶涩。
cd lifecycle
mkdir public
mkdir app
3、分別在 app 中 和 public 中新建 index.html 和 main.js
# index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>React-LifeCycle</title>
</head>
<body>
<div id="container"></div>
<script src="bundle.js"></script>
</body>
</html>
# main.js
import React from 'react' ;
import ReactDOM from 'react-dom' ;
import LifeCycle from './LifeCycle.js' ;
/**
* 定義一個父組件
*/
class Main extends React.Component{
constructor(props){
super(props) ;
this.state = {
name:'junjun'
}
}
render(){
return(
<LifeCycle
umout={this.unmoutComponent}
name={this.state.name}
testComponentWillReceiveProps={this.changeState.bind(this)}
/>
) ;
}
/**
* 卸載組件
*/
unmoutComponent(){
// 這里卸載父組件也會導(dǎo)致卸載子組件
ReactDOM.unmountComponentAtNode(document.getElementById("container"));
}
/**
* 通過修改 state 來修改 props 用來測試 componentWillReceiveProps 方法
*/
changeState(){
this.setState({
name:'TigerChain11111'
})
}
}
ReactDOM.render(
<Main />,
document.getElementById('container')
) ;
在這里我一口氣寫完了絮识,注釋非常詳細绿聘,如果你學(xué)習(xí)過前面章節(jié)的知識,那么這個很容易看懂次舌。
4熄攘、在 app 中再新建 LifeCycle.js
# LifeCycle.js
import React, { Component, PropTypes } from 'react';
/**
* 定義一個生命周期的組件
*/
export default class LifeCycle extends Component {
constructor(props) {
super(props);
console.log("~~ Initial render ~~");
console.log("~~ constructor ~~");
alert("~~ Initial render ~~") ;
alert("~~ constructor ~~") ;
this.state = {
name:'TigerChain'
}
}
/**
* 在掛載之前調(diào)用
*/
componentWillMount(){
console.log("~~ componentWillMout ~~");
alert("~~ componentWillMout ~~") ;
}
render() {
console.log("~~ render ~~");
alert("~~ render ~~") ;
return (
<div>
LifeCycle Demo <p/>
<button onClick={this._changeProps.bind(this)}>changeProps</button><p/>
<button onClick={this._setState.bind(this)}>setState</button><p/>
<button onClick={this._forceWithUpdate.bind(this)}>forceWithUpdate</button><p/>
<button onClick={this._unmout.bind(this)}>unmout</button><p/>
<button onClick={this.koukou.bind(this)}>parentChangeProps</button> <p/>
</div>);
}
/**
* 測試 ComponentWillReceiveProps 方法
*/
koukou(){
this.props.testComponentWillReceiveProps() ;
}
/**
* 在掛載之后調(diào)用
*/
componentDidMount(){
console.log("~~ componentDidMout ~~");
alert("~~ componentDidMout ~~") ;
}
/**
* 組件掛載之后 當(dāng)調(diào)用 setState() 的時候 如果此方法返回 true ,則會重新渲染彼念,否則不會
*/
shouldComponentUpdate(nextProps, nextState){
console.log("~~ shouldComponentUpdate ~~");
console.log("shouldComponentUpdate nextState",nextState);
alert("~~ shouldComponentUpdate ~~"+nextState) ;
return true ;
}
/**
* props 改變的時候調(diào)用
*/
componentWillReceiveProps(nextProps){
console.log("~~ componentWillReceiveProps ~~");
alert("~~ componentWillReceiveProps ~~") ;
}
/**
* shouldComponentUpdate 返回 true 的時候 將要更新
*/
componentWillUpdate(nextProps, nextState){
console.log("componentWillUpdate nextState",nextState);
console.log(this.state.name);
console.log("~~ componentWillUpdate ~~");
alert("~~ componentWillUpdate ~~") ;
}
/**
* 組件已經(jīng)更新
*/
componentDidUpdate(){
console.log("~~ componentDidUpdate ~~");
alert("~~ componentDidUpdate ~~") ;
}
/**
* 組件將要卸載
*/
componentWillUnmount(){
console.log("~~ componentWillUnmount ~~");
alert("~~ componentWillUnmount ~~") ;
}
/**
* 組件卸載的方法
*/
_unmout(){
this.props.umout();
}
_forceWithUpdate(){
this.forceUpdate();
}
/**
* 修改屬性
*/
_changeProps(){
this.setState({
name:'TigerChain1'
})
}
/**
* 修改 state 方法
*/
_setState(){
var that = this ;
if((that.state.name === "TigerChain1") || (that.state.name="TigerChain")){
that.setState({
name:'TigerChainJun'
});
}
}
}
我們在這里把組件生命周期的 demo 就寫完了挪圾,具體可以看注釋。
5逐沙、添加 react react-dom babel 等插件依賴
yarn add react react-dom babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0 webpack webpack-dev-server --dev
這里也不多說哲思,如果不懂的話,可以查看 webpack 這一節(jié)酱吝。
6也殖、在項目根目錄新建 .babelrc 文件并輸入以下內(nèi)容
{
"presets": ["react", "es2015","stage-0"]
}
7、在根目錄新建 webpack.config.js 并配置
# webpack.config.js
module.exports = {
entry: __dirname+"/app/main.js",
output:{
path:__dirname + "/public",
filename:"bundle.js"
},
module: {
loaders: [
//babel配置
{
test:/\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
},
devServer:{
contentBase: "./public",//本地服務(wù)器所加載的頁面所在的目錄
historyApiFallback: true,//不跳轉(zhuǎn)
inline: true//實時刷新
}
}
8务热、配置腳本 package.json
{
"name": "11-lifecycle",
"version": "1.0.0",
"main": "index.js",
"author": "TigerChain",
"license": "ISC",
"scripts":{
"start":"webpack-dev-server --progress --port 8888"
},
"devDependencies": {
"babel-core": "^6.24.0",
"babel-loader": "^6.4.1",
"babel-preset-es2015": "^6.24.0",
"babel-preset-react": "^6.23.0",
"babel-preset-stage-0": "^6.22.0",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"webpack": "^2.3.2",
"webpack-dev-server": "^2.4.2"
}
}
9忆嗜、運行查看 yarn start 并在瀏覽器中輸入 localhost:8888 如果不出什么問題,那么我們就可以看到如下界面
圖中就完整的展示了 React 組件的生命周期崎岂。我們回過頭再去看前面的生命周期圖捆毫,就能很好的理解了。請大家務(wù)必照著 demo 敲一遍代碼冲甘,以便加深理解绩卤。(老鳥直接略過)
到此為止途样,我們的 React 組件的生命周期就講完了。
如果喜歡濒憋,就點個喜歡吧何暇。
Demo 地址
https://github.com/tigerchain/react-lesson/tree/master/lesson02/11-lifecycle