React入門系列(四)組件的生命周期

React的核心是組件,組件在創建和渲染的過程中,需要調用固定的鉤子函數,也稱為組件的“生命周期”。利用生命周期函數,可以做初始化工作,并在渲染過程中實現一些特定功能。

1. 生命周期函數

組件的整個生命周期會涉及如下函數:

鉤子函數 說明
getDefaultProps 設置props默認配置
getInitialState 設置state默認配置
componentWillMount 組件被注入DOM之前被調用
render 渲染組件時被調用
componentDidMount 組件被注入DOM之后被調用
componentWillReceiveProps 掛載的組件接收到新的props時被調用
shouldComponentUpdate 指定是否更新props和state
componentWillUpdate 更新組件時,渲染之前被調用
componentDidUpdate 更新組件時,渲染之后被調用
componentWillUnMount 卸載組件

可以參考下圖(來自網絡)進一步了解整個流程。

react life cycle.jpg

這里特殊說明兩個方法:getDefaultPropsgetInitialState

  • React.createClass()函數創建組件,調用的是這兩個鉤子函數。
  • ES6類方法創建的組件,初始化props用的是靜態屬性defaultProps;初始化state是在構造函數constructor里做的。

總結:

  • props更改時,會依次調用componentWillReceiveProps -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
  • state更改時,會依次調用shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
小貼士

shouldComponentUpdate 是一個非常重要的鉤子函數,這個函數默認返回true。

在React中,調用setState方法,React不會立即對其更新,而是將其標記為“臟”狀態
(組件狀態更新不會立刻生效,React使用事件輪詢對變更內容進行批量繪制)。
當事件輪詢結束后,React將“臟”組件及其子節點進行重繪,所有后代節點的render方法都會被調用,哪怕它們沒法發生變化。

通過shouldComponentUpdate方法,可以阻止子樹的重繪
(自行實現該方法并返回false,React會跳過該組件及其子組件的重繪過程)。

--- 參考《Pro React》

下面,我們來看一個真實例子,觀察組件生命周期的變換(采用ES6類模式)。

2. 組件實例

class DangerButton extends React.Component {
    /*類型檢查*/
    static propTypes = {
        onClick: React.PropTypes.func,
        text: React.PropTypes.string
    };

    /*初始化props值*/
    static defaultProps = {
        type: 'btn'
    };

    constructor(props) {
        super(props);
        // 初始化state值
        this.state = {count: 0};
        this.increaseCount = this.increaseCount.bind(this);
    }

    increaseCount() {
        this.setState({count: this.state.count + 1});
    }

    getObjectValues(obj){
        var array = [];
        for(let key in obj){
            array.push(key + ":" + obj[key]);
        }
        return array.join(";");
    }

    /*----------------start: life cycle---------------*/
    /*組件被注入DOM之前*/
    componentWillMount() {
        var button = document.getElementById('dangerBtn');
        console.log("componentWillMount:" + button);
    }
    /*組件被注入DOM之后*/
    componentDidMount() {
        var button = document.getElementById('dangerBtn');
        console.log("componentDidMount:" + button);
    }

    /*掛載的組件接收到新的props時被調用*/
    componentWillReceiveProps(nextProps){
        console.log("componentWillReceiveProps:" + nextProps);
    }

    /*指定是否更新props和state*/
    shouldComponentUpdate(nextProps, nextState){
        console.log("shouldComponentUpdate-true!");
        return true;
    }

    /*更新組件時,渲染之前*/
    componentWillUpdate(nextProps, nextState){
        console.log("componentWillUpdate-nextProps:" + this.getObjectValues(nextProps));
        console.log("componentWillUpdate-nextState:" + this.getObjectValues(nextState));
    }

    /*更新組件時,渲染之后*/
    componentDidUpdate(prevProps, prevState){
        console.log("componentDidUpdate-prevProps:" + this.getObjectValues(prevProps));
        console.log("componentDidUpdate-prevState:" + this.getObjectValues(prevState));
    }

    /*卸載組件*/
    componentWillUnMount() {
        var button = document.getElementById('dangerBtn');
        console.log("componentDidMount:" + button);
    }

    render() {
        console.log("rendering....");
        return (<div>
            <button id="dangerBtn" className='red' onClick={this.increaseCount}>
                <span className='white'>{this.props.text}</span>
            </button>
            <p>Click count: {this.state.count}</p>
        </div>);
    }
    /*----------------end: life cycle---------------*/
}
ReactDOM.render(
    <DangerButton text="click it!"/>,
    document.getElementById('container')
);

第一次渲染DangerButton組件時,控制臺打印如下信息:

componentWillMount:null
rendering....
componentDidMount:[object HTMLButtonElement]

可見,渲染組件的componentWillMount階段,真實DOM還沒有生成;到了componentDidMount階段,組件才真正被加載到DOM中。

然后,點擊DangerButton,count值加一,控制臺打印如下信息:

shouldComponentUpdate-true!
componentWillUpdate-nextProps:text:click it!;type:btn
componentWillUpdate-nextState:count:1
rendering....
componentDidUpdate-prevProps:text:click it!;type:btn
componentDidUpdate-prevState:count:0

可見,如果組件自身的state更新后(點擊button,觸發onClick事件),會依次執行shouldComponentUpdate,componentWillUpdaterendercomponentDidUpdate函數。

小結

在組件整個生命周期中,涉及到兩種變量來傳遞/存儲值,propstate。那么,它們的使用場景是什么?有什么區別呢?下一節,我們將繼續探索......

下一節:React入門系列(五)props和state

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容