生命週期回顧與再認識

生命週期

  1. 生命週期是一個組件從建立到銷燬的過程。
  2. 當組建實例被建立而且插入到DOM中,須要調用的函數,就是生命週期函數。
  3. 也就是說,組件加載完成先後、組件更新數據、組件銷燬,所觸發的一系列的方法。

1.第一階段--初始化階段

組件建立到首次渲染到頁面html

  1. constructor() 構造函數,在建立組件的時候調用一次
  2. componentWillMount() 在組件即將被掛載的時候調用一次
  3. render() 渲染
  4. componentDidMount() 在組件被掛載完成的時候調用一次,能夠在這裏使用refs屬性,由於組件已經被渲染出來了。
  5. 代碼
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')
);
複製代碼

打印的順序:後端

解析:

  1. undefined是在componentWillMount()中打印出來的,更新了setState卻仍是undefined,說明該方法是異步的,因此用了定時器,兩秒後打印出來了傳的值。
  2. 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')
);
複製代碼

點擊前: bash

點擊後:

當更新state的時候,會從新觸發render();app


2.第二階段--更新階段

狀態更新引發的變化dom

  1. componentWillReceiveProps(nextProps) 父組件的更新會觸發子組件的這個函數異步

  2. shouldComponentUpdate(nextProps, nextState) return false/true 是否須要從新渲染,默認值爲true,表示更新;false會阻止render調用函數

  3. componentWillUpdate(nextProps, nextState) 即將更新,不能修改屬性與狀態,用於日誌打印和數據獲取測試

  4. render() 渲染ui

  5. componentDidUpdata() 完成更新

  6. 參數:

    1. nextProps:父組件更新的時候帶來的數據  
         2. nextState:子組件當前的狀態  
    複製代碼
  7. 代碼

//子組件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')
);
複製代碼

效果圖:

分析:

  1. 因爲List是App的子組件,因此App執行render的時候,會將List也渲染了,因此會打印"02-構造函數01",而List中也會執行render,打印"02-渲染組件05",以後組件完成加載。
  2. 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;
}
複製代碼

點擊後的效果:

.第三階段--銷燬階段

組件在銷燬以前

  1. componentWillUnmount() 組件即將銷燬

總結

初始化和銷燬階段在組件的整個生命週期中只會出現一次 更新階段會在組件每次更新中都會執行

相關文章
相關標籤/搜索