<react學習筆記(8)>生命週期回顧與再認識

liangsheng0111發表於2018-12-25

生命週期

  1. 生命週期是一個元件從建立到銷燬的過程。
  2. 當組建例項被建立並且插入到DOM中,需要呼叫的函式,就是生命週期函式。
  3. 也就是說,元件載入完成前後、元件更新資料、元件銷燬,所觸發的一系列的方法。

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

元件建立到首次渲染到頁面

  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')
);
複製程式碼

列印的順序:

<react學習筆記(8)>生命週期回顧與再認識
解析:

  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')
);
複製程式碼

點選前:

<react學習筆記(8)>生命週期回顧與再認識
點選後:

<react學習筆記(8)>生命週期回顧與再認識

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


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

狀態更新引起的變化

  1. componentWillReceiveProps(nextProps) 父元件的更新會觸發子元件的這個函式

  2. shouldComponentUpdate(nextProps, nextState) return false/true 是否需要重新渲染,預設值為true,表示更新;false會阻止render呼叫

  3. componentWillUpdate(nextProps, nextState) 即將更新,不能修改屬性與狀態,用於日誌列印和資料獲取

  4. render() 渲染

  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')
);
複製程式碼

效果圖:

<react學習筆記(8)>生命週期回顧與再認識
分析:

  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')
);
複製程式碼

點選後的效果圖;

<react學習筆記(8)>生命週期回顧與再認識

由列印的結果可知,componentWillReceiveProps()方法得到父組將更新的資料,可是頁面上並沒有改變,也就是說子元件的資料並沒有更新,此時通過shouldComponentUpdate()方法更新。

程式碼分析:
判斷當前子元件的title屬性是否與父元件傳來的陣列相同,如果不同,走if判斷,更新資料,因為資料更新了,所以會再次觸發render方法,更新頁面

shouldComponentUpdate(nextProps, nextState) {
    if( this.state.title !== nextProps.title){
        this.setState({
            title : nextProps.title
        })
    };
    return true;
}
複製程式碼

點選後的效果:

<react學習筆記(8)>生命週期回顧與再認識

.第三階段--銷燬階段

元件在銷燬之前

  1. componentWillUnmount() 元件即將銷燬

總結

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

相關文章