元件生命週期函式
React 主動呼叫的方法,也可重寫這些方法
當元件例項被建立並插入 DOM
中時,其生命週期呼叫順序如下:
constructor(props)
如果不需要初始化 state 或 不進行方法繫結,則不需要使用該方法
在元件掛載之前會先呼叫該方法,在實現建構函式時必須先呼叫super(props)
方法,否則會出現BUG
通常,建構函式僅用於兩種情況:1. 初始化 state
2. 為事件處理函式繫結例項
在該方法中不要使用 setState()
方法,在其他方法中使用setState()
改變 state
為什麼 props 複製給 state 會產生 bug
constructor(props) {
super(props);
// 不要在這裡呼叫 this.setState()
this.state = {
counter: 0,
name:props.name // 嚴禁這樣賦值,props.name值更新時 state.name並不會更新
};
this.handleClick = this.handleClick.bind(this);
}
static getDerivedStateFromProps() (此方法不常用)
此方法會在
render
方法之前呼叫,並且初始化和資料更新時都會呼叫,它返回一個物件更新 state,如果返回null 則不更新任何內容。
此方法適用於 state 值在任何時候都取決於props 的情況。
render()
render 是 class 元件必須實現的方法
當該方法被呼叫時,它會監測 props 和 state 的變化,並且返回以下型別之一:
React 元素
:通過JSX建立,渲染成對應的DOM節點或自定義元件- 陣列或fragments: 使render方法可以返回多個元素 frgments
Portals
:可以渲染子節點到不同的DOM子樹匯中portals- 字串或數值型別: 在DOM中會被渲染為文字節點、
Boolean 或 null
:什麼都不渲染
render方法最好為純函式,即在不修改元件 state
情況下,每次呼叫時都返回相同的結果,並且不會直接與瀏覽器互動
如果要和瀏覽器互動,可以在其他生命週期函式中執行,注意:
shoouldComponentUpdate
方法中返回false,將不會呼叫render方法
class Example extemds React.Component{
shouldComponentUpdate(nextProps, nextState){
return false
}
render(){ // 不會執行
<div>owen</div>
}
}
componentDIdMount()
此方法會在元件掛載後(插入DOM樹中)呼叫,初始化的資料的好地方
元件的 props
或 state
發生變化會觸發更新。元件更新的生命週期呼叫順序如下:
static getDerivedStateFromProps() (此方法不常用)(已解釋)
shouldComponentUpdate(nextProps, nextState) (此方法不常用)
當state 或 props 變化時該方法會在渲染執行前呼叫預設返回值為true,首次載入不會被呼叫
根據該方法的返回值判斷元件輸出是否受當前 state 或 props 更改的影響。預設為 state 每次更新重新渲染
此方法進僅做為效能優化的方式存在,不要企圖依靠此方法來“阻止”渲染,因為這可能會產生 bug。你應該考慮使用內建的 PureComponent 元件,而不是手動編寫 shouldComponentUpdate()。PureComponent 會對 props 和 state 進行淺層比較,並減少了跳過必要更新的可能性。
render()(已解釋)
getSnapshotBeforeUpdate() (此方法不常用)
此方法在最近一次渲染輸出(提交到DOM節點)之前呼叫。使元件能在傳送更改前從DOM中捕獲一些資訊(如 位置)。此生命週期的返回值將作為引數傳遞給
componentDidUpdate()
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 我們是否在 list 中新增新的 items ?
// 捕獲滾動位置以便我們稍後調整滾動位置。
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 如果我們 snapshot 有值,說明我們剛剛新增了新的 items,
// 調整滾動位置使得這些新 items 不會將舊的 items 推出檢視。
//(這裡的 snapshot 是 getSnapshotBeforeUpdate 的返回值)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
上述示例中,重點是從 getSnapshotBeforeUpdate 讀取 scrollHeight 屬性,因為 “render” 階段生命週期(如 render)和 “commit” 階段生命週期(如 getSnapshotBeforeUpdate 和 componentDidUpdate)之間可能存在延遲。
componentDidUpdate(prevProps, prevState, snapshot)
此方法會在資料更新後立即呼叫,首次載入不會被呼叫,在此方法中使用
setState
必須將它放到條件語句中,否則會導致死迴圈。還會導致額外的重新渲染,影響效能
componentDidUpdate(prevProps) {
// 典型用法(不要忘記比較 props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
注意:如果 shouldComponentUpdate() 返回值為 false,則不會呼叫 componentDidUpdate()。
當元件從 DOM
中移除時會呼叫如下方法:
componentWillUnmount()
此方法會在元件解除安裝銷燬前呼叫,可以執行必要的清理操作,如 定時器,取消網路請求,或清除componentDidMount() 中建立的訂閱等。
當渲染過程,生命週期,或子元件的建構函式中丟擲錯誤時,會呼叫如下方法:
Error boundaries:捕獲渲染期間及整個樹的函式傳送的錯誤,渲染降級 UI,但自身的錯誤無法捕獲 React 16中的錯誤處理
static getDerivedStateFromError(error) (此方法不常用)
次生命週期會在後代元件丟擲錯誤後呼叫,將錯誤作為引數,返回一個值更新state,在渲染期間不允許出現副作用,建議使用 componentDidCatch()
componentDidCatch(error, info) (此方法不常用)
此方法在後代元件丟擲錯誤後被呼叫
如果發生錯誤,可以通過呼叫 setState
使用 componentDidCatch()
渲染降級 UI,但在未來的版本中將不推薦這樣做。 可以使用靜態 getDerivedStateFromError()
來處理降級渲染。
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染可以顯降級 UI
return { hasError: true };
}
componentDidCatch(error, info) {
// "元件堆疊" 例子:
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
logComponentStackToMyService(info.componentStack);
}
render() {
if (this.state.hasError) {
// 你可以渲染任何自定義的降級 UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
Example
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value:null
};
}
static getDerivedStateFromProps(props, state) {
// 例項化元件之後以及在重新呈現元件之前呼叫新的靜態生命週期。它可以返回要更新的物件state,或null指示新物件props不需要任何state更新。
}
componentDidMount() { // 元件被渲染到 DOM 中後執行
console.log('DidMount: 1')
}
shouldComponentUpdate(){
// 更新前
}
getSnapshotBeforeUpdate(){
//
}
componentDidUpdate() {
// 更新後
}
static getDerivedStateFromError() {
// 出錯時
}
componentDidCatch(){
// capture error
}
compoentwillUnmount(){ // 元件被刪除的時候
console.log('UnMount: end')
}
render() {
return (
<button className="square" onClick = {()=>{this.setState({value:'X'})}
}>
{this.state.value}
</button>
);
}
}