React:完整的生命週期及方法

什麼是生命週期

在具備許多組件的應用程序中,當組件被銷燬時釋放所佔用的資源是很是重要的。html

組件從 被建立被銷燬 的過程稱爲組件的生命週期。react

組件的生命週期可分紅三個狀態:ajax

  • Mounting(掛載時)
  • Updating(更新時)
  • Unmounting(卸載時)

組件的生命週期可分爲三個階段:api

  • Render: 用於計算當前的狀態/更新信息,會根據產生的任務的優先級,安排任務的調度(schedule)
  • Pre-commit: commit 以前,能夠獲取當前 DOM 的快照(snap)
  • Commit: 把全部更新都 commit 到 DOM 樹上

生命週期方法

圖解

常見方法版

react-lifecycle-1.png ( 圖片來源:projects.wojtekmaj.pl/react-lifec…瀏覽器

完整方法版

react-lifecycle.png

( 圖片來源:projects.wojtekmaj.pl/react-lifec…安全

方法

- contructor

constructor(props);
複製代碼

一般,在 React 中,構造函數僅用於如下兩種狀況:性能優化

  • 經過給 this.state 賦值對象來初始化內部 state。( 惟一能夠直接修改 state 的地方)
  • 爲事件處理函數綁定實例

constructor() 函數中不要調用 setState() 方法。markdown

constructor(props) {
  super(props);
  // 不要在這裏調用 this.setState()
  this.state = { counter: 0 };
  this.handleClick = this.handleClick.bind(this);
}
複製代碼

- getDerivedStateFromProps

static getDerivedStateFromProps(props, state)
複製代碼

這個方法是 「如何用 props 初始化 state 」 的最佳實踐。網絡

⚠️ 注意,該方法在每次 render 前都會被調用。函數

此方法適用於罕見的用例(表單控件獲取默認值)。當 state 是從 props 獲取時,就必需要維護二者的一致性,這將會增長複雜度和 bug

- shouldComponentUpate

shouldComponentUpdate(nextProps, nextState);
複製代碼

propsstate 發生變化時,shouldComponentUpdate() 會在渲染執行以前被調用。返回值默認爲 true。首次渲染或使用 forceUpdate() 時不會調用該方法。

此方法 僅做爲性能優化 的方式而存在。它的工做通常能夠由 PrueComponent 自動實現。

後續版本,React 可能會將 shouldComponentUpdate 僅視爲提示,而且,當返回 false 時,仍可能致使組件從新渲染。

- render

render();
複製代碼

用於描述 DOM 結構,組件中惟一必須實現的方法。

- getSnapshotBeforeUpdate

getSnapshotBeforeUpdate(prevProps, prevState);
複製代碼

能在組件發生更改以前從 DOM 中捕獲一些信息(例如,滾動位置)。今生命週期方法的任何返回值將做爲參數傳遞給 componentDidUpdate()

- componentDidMount

componentDidMount();
複製代碼

在組件掛載後(插入 DOM 樹中)當即調用。在這裏能夠安全操做 DOM 節點、發送ajax 請求(DOM 節點的初始化)或一些反作用的事情(訂閱)

若是你在這裏調用了 setState,它將觸發額外渲染,雖然此渲染會發生在瀏覽器更新屏幕以前,但會致使性能問題。

- componentDidUpdate

componentDidUpdate(prevProps, prevState, snapshot);
複製代碼

在更新後會被當即調用。首次渲染不會執行此方法。

⚠ 注意, 若是直接調用 setState(),它必須被包裹在一個條件語句裏,不然會致使死循環。

- componentWillUnmount

componentWillUnmount();
複製代碼

在組件卸載及銷燬以前直接調用,作一些資源釋放操做,例如,清除 timer,取消網絡請求或清除在 componentDidMount() 中建立的訂閱等。

⚠️ 注意:不該調用 setState(),由於該組件將永遠不會從新渲染。

演示

Clock

用官方的經典 Clock 組件,能夠清楚的展現出常見生命週期方法的應用:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() };
  }

  componentDidMount() {
    this.timerID = setInterval(() => this.tick(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  componentDidUpdate() {
    console.log("component did update!");
  }

  tick() {
    this.setState({
      date: new Date(),
    });
  }

  render() {
    return (
      <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>
    );
  }
}

ReactDOM.render(<Clock />, document.getElementById("root"));
複製代碼

在組件第一次掛載時,設置一個定時器;同時,在組件卸載時,清除定時器。

state.date 發生改變時,會引起組件的從新渲染。

getSnapshotBeforeUpdate 實踐

以特殊方式處理滾動位置的聊天線程:由於每一條新消息的置頂設定,沒法讓頁面固定在某處,因此在每次更新前都須要計算調整滾動條的位置。

class ScrollList extends PureComponent {
  state = {
    messages: [],
  };
  getSnapshotBeforeUpdate() {
    return this.rootNode.scrollHeight;
  }

  componentDidUpdate(prevProps, prevState, prevScrollHeight) {
    const scrollTop = this.rootNode.scrollTop;
    if (scrollTop < 5) return;
    this.rootNode.scrollTop =
      scrollTop + (this.rootNode.scrollHeight - prevScrollHeight);
  }

  render() {
    return (
      <div className="scroll-list" ref={(n) => (this.rootNode = n)}> {this.state.messages.map((msg) => ( <div>{msg}</div> ))} </div>
    );
  }
}
複製代碼

DOM 更新前,經過 getSnapshotBeforeUpdate 獲取原來的元素內容高度( scrollHeight ),並做爲第三個參數傳給 componentDidUpdate

componentDidUpdate 中,經過添加元素內容高度差值( this.rootNode.scrollHeight - prevScrollHeight ),調整滾動條位置( scrollTop )。

參考資料

React 入門

相關文章
相關標籤/搜索