目錄
-
1.react元件的兩種建立寫法
-
2.元件的生命週期在不同狀態下的執行順序
-
3.元件各生命週期的應用
1.react元件的兩種建立寫法
第一種ES5寫法,React.createClass
React.createClass({
getDefaultProps() {
return {
key1:value1
}
},
getInitialState() {
return {
state1:state1
}
}
});
第二種是ES6寫法,繼承React.Component類
export default class Test1 extends React.Component {
constructor (props) {
super(props);
this.state = {
state1: state1
}
}
static defaultProps = {
data: 2,
};
static propTypes = {
optionsData: React.PropTypes.array,
onSelect: React.PropTypes.func,
selectedOption: React.PropTypes.object,
topStyle: React.PropTypes.any,
placeholder: React.PropTypes.string
}
}
getDefaultProps、getInitialState是在createClass時呼叫的方法,而在繼承component類時,getDefaultProps方法對應給類新增靜態屬性 defaultProps ,getInitialState 對應在類的建構函式中設定 state屬性
2.元件的生命週期在不同狀態下的執行順序
元件首次裝載(first-Mount):
-
getDefaultProps() →
-
getInitialState() →
-
componentWillMount() →
-
render() →
-
componentDidMount()
解除安裝元件時(Unmount):componentWillUnmount()
當重新裝載元件時(Re-Mount):
-
getInitialState()→
-
componentWillMount()→
-
render() →
-
componentDidMount(),
-
但並不執行 getDefaultProps; defaultProps是放在元件類上的static屬性
當再次渲染元件時(Re-Render),此時按順序執行
-
componentWillReceiveProps(nextProps )(元件接收到新的props才會呼叫,只是改變state時不呼叫)→
-
shouldComponentUpdate(元件接收到新的props才會呼叫,只是改變state時不呼叫)→
-
componentWillUpdate→
-
render →
-
componentDidUpdate。
單獨呼叫setState的重新渲染
-
componentWillUpdate→
-
render →
-
componentDidUpdate
1、在單頁應用中,用react-router的history做頁面跳轉時,是將當前route的所有元件解除安裝,再跳轉回來時是重新裝載元件,而不是首次裝載。
2、在使用react-native的Navigator時,每次push新頁面的時候是首次載入,舊頁面沒有解除安裝,在pop新頁面的時候,新頁面會解除安裝 呼叫Unmount,舊頁面是重新渲染
-
componentWillReceiveProps→
-
componentWillUpdate→
-
render →
-
componentDidUpdate。
,不是重新裝載,也沒有重新渲染的shouldComponentUpdate控制,所以pop回來肯定重新渲染。
3、元件在記憶體中裝載過一次之後,元件的defaultProps就初始化了,之後裝載就不會重新設定。
4、父元件的render都會引起子元件的重新渲染。
5、 不能在componentWillUpdate ,render和componentDidUpdate 中呼叫setState
3.元件各生命週期的應用
3.1 getDefaultProps方法 或者 defaultProps 物件
-
只在元件類建立的時候呼叫一次,之後會被快取起來。
-
defaultProps在元件例項之前建立,例項間共享。
-
會和父元件設定的props進行合併。
3.2 getInitialState方法或constructor的state屬性
專案中會把元件用到的state初始化在這裡
constructor (props) {
super(props);
this.state = {
poi: null,
activeTabId: null,
cartCount: Shopcart.size(),
domSize:{
headerHeight: 100,
bannerHeight: 200,
categoryTabHeight: 100,
},
hiddenBanner: false //是否隱藏banner
};
}
3.3 componentWillMount()
元件初次render之前呼叫,如果在此方法中呼叫setState,render將感知到更新後的state,並且只執行這一次render,可以在此方法中fetch資料,不需要dom操作的資料獲取。
3.4 render()
元件渲染的方法,是元件唯一的必須實現的方法,在該方法中,我們可以通過props和state渲染不同的元件。返回null或者false代表不渲染任何東西。
render () {
return (
<header className="header-wrapper">
<div className="header header-normal">
{this.renderLeftComponent()}
<span>{this.props.title || `美團商超`}</span>
{this.renderRightComponent()}
</div>
</header>
);
}
3.5 componentDidMount()
元件裝載後呼叫的方法,因為該方法呼叫的時候,元件已經裝載,並且該方法不在render的迴圈當中,一般在該方法中做一些fetch資料或者改變state的方法。
還可以通過ReactDOM.findDOMNode(_this.refs.wrapper) 來獲取DOM節點 進行操作。
componentDidMount() {
this.mounted = true;
if(this.props.poi){
this.fetchCategoryTabs(this.props.poi.poiId);
}
if(!this.isCalculate) {
this.calculateWidth();
}
}
3.6 componentWillReceiveProps(nextProps)
在元件接收到新的 props 的時候呼叫。在初始化渲染的時候,該方法不會呼叫。可以在該方法中判斷,當props變化時,是否再去重新fetch資料,setState。
componentWillReceiveProps (nextProps) {
if(nextProps.poi &&(nextProps.poi != this.props.poi)) {
this.fetchBannerList(nextProps.poi.poiId);
}
}
3.7 shouldComponentUpdate(nextProps, nextState)
在接收到新的props或者state變化時,被呼叫,該方法在初始化渲染和forceUpdate的時候不會被呼叫。
預設返回true,如果返回false,則render不會執行。可以在這個方法中來阻止不必要的render,因為有時是因為父元件的render引起的子元件不必要的render。
shouldComponentUpdate(nextProps, nextState) {
const isStateChanged = Object.keys(nextState).some(key=> {
return nextState[key] !== this.state[key]
});
const isPropsChanged = Object.keys(nextProps).some(key=> {
return nextProps[key] !== this.props[key]
});
return isStateChanged || isPropsChanged
}
3.8 componentWillUpdate(nextProps, nextState)
在接收到新的 props 或者 state 之前立刻呼叫。在初始化渲染的時候該方法不會被呼叫。使用該方法做一些更新之前的準備工作。你不能在剛方法中使用 this.setState()。如果需要更新 state 來響應某個 prop 的改變,請使用 componentWillReceiveProps。 專案中應用不多。
3.9 componentDidUpdate
在元件的更新已經同步到 DOM 中之後立刻被呼叫。該方法不會在初始化渲染的時候呼叫。使用該方法可以在元件更新之後操作 DOM 元素。
有些操作可能需要操作DOM元素,並且在第一次componentDidMount時還沒有達到條件,所以需要在componentDidUpdate時再做操作,但是componentDidUpdate在render的迴圈函式中,
所以需要設定變數做控制。
下面例子中 this.isCalculate 就是判斷是否計算過的變數。
componentDidMount() {
this.mounted = true;
if(this.props.poi){
this.fetchCategoryTabs(this.props.poi.poiId);
}
if(!this.isCalculate) {
this.calculateWidth();
}
}
componentDidUpdate () {
if(!this.isCalculate) {
this.calculateWidth();
}
}
calculateWidth () {
if(this.isCalculate) {
return;
}
let tablist = this.state.categoryTabs;
if(tablist.length == 0) {
return;
}
let tabsDOM = this.refs.tablist,
childrensDOM = tabsDOM.childNodes,
container = this.refs.tabcontainer,
wrapper = this.refs.wrapper,
// 橫向滾動寬度
scrollwidth = 5;
for(let i=0; i<childrensDOM.length; i++){
let childDOM = childrensDOM[i];
scrollwidth += childDOM.clientWidth + parseInt(childDOM.style.marginRight);
}
scrollwidth = Math.max(tabsDOM.clientWidth,scrollwidth);
this.setState({tabsWidth: scrollwidth + `px`});
this.props.setCategoryTabHeight(wrapper.offsetHeight);
this.isCalculate = true;
}
3.10 componentWillUnmount
在元件從 DOM 中移除的時候立刻被呼叫。在該方法中執行任何必要的清理,比如無效的定時器,或者清除在 componentDidMount 中建立的 DOM 元素。
可以記錄元件的mount狀態,在 componentDidMount 中設定this.mounted = true 。 在componentWillUnmount 中設定 this.mounted = false。