組件生命周期函數 React 主動調用的方法,也可重寫這些方法 "生命周期圖譜" 當組件實例被創建並插入 中時,其生命周期調用順序如下: constructor(props) 如果不需要初始化 state 或 不進行方法綁定,則不需要使用該方法 在組件掛載之前會先調用該方法,在實現構造函數時必須先調 ...
組件生命周期函數
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>
);
}
}