生命週期
- 生命週期是一個元件從建立到銷燬的過程。
- 當組建例項被建立並且插入到DOM中,需要呼叫的函式,就是生命週期函式。
- 也就是說,元件載入完成前後、元件更新資料、元件銷燬,所觸發的一系列的方法。
1.第一階段--初始化階段
元件建立到首次渲染到頁面
constructor()
建構函式,在建立元件的時候呼叫一次componentWillMount()
在元件即將被掛載的時候呼叫一次render()
渲染componentDidMount()
在元件被掛載完成的時候呼叫一次,可以在這裡使用refs屬性,因為元件已經被渲染出來了。- 程式碼
class App extends React.Component{
constructor(props) {
super(props);
// 建構函式只執行一行
// this.props.title 讀取父元件的傳遞的資料
// this.state = {} 初始化一個狀態
this.state = {
a: props.title,
b: this.props.title
};
console.log( '01-建構函式1 ' );
}
componentWillMount() {
console.log('02-元件即將被掛載2');
// 這時不能做dom操作,因為還沒有渲染
// 請求後端介面 真實測試的會出現白屏(頁面一直沒有圖片 文字 html結構 )
// this.setState() this.state this.props 都是非同步的
this.setState({
c: '請求的資料'
});
console.log(this.state.c); //undefined
setTimeout(()=>{
console.log( this.state.c ); //請求的資料
},2000);
}
render() {
console.log( '03-開始渲染元件3' )
// 可以在這一步對 state資料進行處理
//console.log( this.state.c )
return (
<div>
{this.state.a}
<hr />
{this.state.b}
<button
ref={btn=>this._btn=btn}
onClick={this.handleClick}
>點選 </button>
</div>
);
}
componentDidMount() {
// 可以在網頁上能夠看到資料(圖片 文字)
// 真實的場景 會在此請求後端資料介面
// 請求回來的資料 會掛載到state裡面
// 放在state裡面的好處
// 1. 當前元件是根據state的資料進行渲染
// 2. state的資料是響應式資料 ,一但資料變化了,就會自動觸發render函式
console.log('04-元件掛載完成啦4');
console.log( this._btn );
this._btn.style.background = 'skyblue';
}
};
ReactDOM.render(
<App title={'傳值給App元件'}></App>,
document.querySelector('#app')
);
複製程式碼
列印的順序:
解析:- undefined是在componentWillMount()中列印出來的,更新了setState卻還是undefined,說明該方法是非同步的,所以用了定時器,兩秒後列印出來了傳的值。
- componentDidMount()元件已經載入完畢,此時可以操作DOM節點,因此可以獲取到button按鈕
demo :點選當前元件的元素執行當前的事件函式更新當前的元件資料b,資料變化就是自動觸發render資料
class App extends React.Component{
constructor(props) {
super(props);
this.state = {
a: props.title,
b: this.props.title
};
console.log( '01-建構函式1 ' );
}
componentWillMount() {
console.log('02-元件即將被掛載2');
this.setState({
c: '請求的資料'
});
console.log(this.state.c);
setTimeout(()=>{
console.log( this.state.c );
},2000);
}
handleClick = ()=>{
this.setState({
b: '點選事件改變了b的資料'
})
}
render() {
console.log( '03-開始渲染元件3' )
//console.log( this.state.c )
return (
<div>
{this.state.a}
<hr />
{this.state.b}
<button
ref={btn=>this._btn=btn}
onClick={this.handleClick}
>點選 </button>
</div>
);
}
componentDidMount() {
console.log('04-元件掛載完成啦4');
this._btn.style.background = 'skyblue';
}
};
ReactDOM.render(
<App title={'傳值給App元件'}></App>,
document.querySelector('#app')
);
複製程式碼
點選前:
點選後:當更新state的時候,會重新觸發render();
2.第二階段--更新階段
狀態更新引起的變化
-
componentWillReceiveProps(nextProps)
父元件的更新會觸發子元件的這個函式 -
shouldComponentUpdate(nextProps, nextState) return false/true
是否需要重新渲染,預設值為true,表示更新;false會阻止render呼叫 -
componentWillUpdate(nextProps, nextState)
即將更新,不能修改屬性與狀態,用於日誌列印和資料獲取 -
render()
渲染 -
componentDidUpdata()
完成更新 -
引數:
1. nextProps:父元件更新的時候帶來的資料 2. nextState:子元件當前的狀態 複製程式碼
-
程式碼
//子元件List
class List extends React.Component {
constructor() {
super();
console.log( '02-建構函式01' );
}
componentWillReceiveProps(nextProps) {
console.log('02-獲取父元件更新的時候帶來的資料02 ',nextProps);
}
shouldComponentUpdate(nextProps, nextState) {
console.log('02-是否將來更新元件03');
return true;
}
componentWillUpdate(nextProps, nextState) {
console.log('02-元件即將被更新04', nextProps, nextState );
// 看自己的需求
}
render() {
console.log('02-渲染元件05');
return (
<div>
<h2> 這是List元件 </h2>
</div>
);
}
componentDidUpdate(prevProps, prevState) {
console.log( '02-元件更新完成啦06', prevProps,prevState )
}
componentWillUnmount() {
console.log('03-List元件即將被銷燬07')
}
}
//父元件App
class App extends React.Component{
constructor(props) {
super(props);
console.log( '01-建構函式1 ' );
this.state = {
p: 'App',
onOff: true
};
}
componentWillMount() {
console.log('01-元件即將被掛載2');
}
componentDidMount() {
console.log('01-元件掛載完成啦4');
}
render() {
console.log( '01-開始渲染元件3' );
return (
<div>
<h1>App</h1>
<List title={this.state.p}></List>
</div>
);
}
}
ReactDOM.render(
<App></App>,
document.querySelector('#app')
);
複製程式碼
效果圖:
分析:- 由於List是App的子元件,所以App執行render的時候,會將List也渲染了,所以會列印"02-建構函式01",而List中也會執行render,列印"02-渲染元件05",之後元件完成載入。
- componentWillReceiveProps()是在當父元件更新資料時 才會觸發,下一個例子。
設定點選事件,修改父元件的資料,觸發更新階段的方法
class List extends React.Component {
constructor(props) {
super(props);
//console.log( '02-建構函式01' );
this.state = {
list: '這是list資料',
//接收父元件傳來的值
title : this.props.title
};
console.log(this.state.title);
}
componentWillReceiveProps(nextProps) {
console.log('02-獲取父元件更新的時候帶來的資料02 ',nextProps);
}
shouldComponentUpdate(nextProps, nextState) {
console.log('02-是否將來更新元件03',nextProps, nextState);
return true;
}
componentWillUpdate(nextProps, nextState) {
console.log('02-元件即將被更新04', nextProps, nextState );
// 看自己的需求
}
render() {
console.log('02-渲染元件05');
return (
<div>
<h2> 這是List元件 </h2>
{this.state.title}
</div>
);
}
componentDidUpdate(prevProps, prevState) {
console.log( '02-元件更新完成啦06', prevProps,prevState )
}
}
//父元件App
class App extends React.Component{
constructor(props) {
super(props);
this.state = {
p : "abc"
};
}
handleClick = () =>{
this.setState({
p : "點選事件改變了App的資料"
})
}
render() {
return (
<div>
<h1>App</h1>
<List title={this.state.p}></List>
<button onClick={this.handleClick}>點選事件</button>
</div>
);
}
}
ReactDOM.render(
<App ></App>,
document.querySelector('#app')
);
複製程式碼
點選後的效果圖;
由列印的結果可知,componentWillReceiveProps()方法得到父組將更新的資料,可是頁面上並沒有改變,也就是說子元件的資料並沒有更新,此時通過shouldComponentUpdate()方法更新。
程式碼分析:
判斷當前子元件的title屬性是否與父元件傳來的陣列相同,如果不同,走if判斷,更新資料,因為資料更新了,所以會再次觸發render方法,更新頁面
shouldComponentUpdate(nextProps, nextState) {
if( this.state.title !== nextProps.title){
this.setState({
title : nextProps.title
})
};
return true;
}
複製程式碼
點選後的效果:
.第三階段--銷燬階段
元件在銷燬之前
componentWillUnmount()
元件即將銷燬
總結
初始化和銷燬階段在元件的整個生命週期中只會出現一次
更新階段會在元件每次更新中都會執行