05. react 初次見面---State&生命週期

    到目前爲止咱們只學習了一種方法來更新UI。調用 ReactDOM.render( ) 方法來改變輸出。javascript

    在前面博客中有一個時鐘的例子代碼:java

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(
    element,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

    將時鐘封裝爲Clock組件數組

function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

1. 將函數轉換爲類

    能夠經過5個步驟將函數組件 轉換爲 類組件瀏覽器

  • 建立一個名稱擴展爲 React.Component 的ES6 類
  • 建立一個叫作render()的空方法
  • 將函數體移動到 render() 方法中
  • 在 render() 方法中,使用 this.props 替換 props
  • 刪除剩餘的空函數聲明

    使用類就容許咱們使用其它特性,例如局部狀態生命週期鉤子。異步

    時鐘組件被更改成函數

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

2. 爲一個類添加局部狀態

    咱們經過3個步驟將 date 從屬性移動到狀態中。post

  •  在 render( ) 方法中使用 this.state.date 替換 this.props.date;
  •  添加一個類構造函數來初始化狀態 this.state ;
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
  • 從 <Clock /> 元素中移除 date 屬性
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {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')
);

    接下來,咱們將使 Clock 設置本身的計時器並每秒更新一次。性能

3. 將生命週期方法添加到類中

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

    掛載:每當 Clock 組件第一次加載到 DOM 中的時候,咱們都會想生產定時器,這在React中被稱爲掛載(componentDidMount( ){....}fetch

    卸載:每當 Clock 生產的這個 DOM 被移除的時候,咱們也會想要清除定時器,這在 React 中被稱爲卸載( componentWillUnmount( ){....} )。

    這些方法被稱做生命週期鉤子函數。

    在 componentDidMount( ) 鉤子函數中創建定時器,在 componentWillUnmount( ) 鉤子函數中卸載計時器。使用 this.setState( ) 來更新組件局部狀態:

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);
  }

  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')
);

    成功:

                    

    讓咱們快速回顧一下發生了什麼以及調用方法的順序:

  1. 當 <Clock /> 被傳遞給 ReactDOM.render() 時,React 調用 Clock 組件的構造函數。 因爲 Clock 須要顯示當前時間,因此使用包含當前時間的對象來初始化 this.state 。 咱們稍後會更新此狀態。

  2. React 而後調用 Clock 組件的 render() 方法。這是 React 瞭解屏幕上應該顯示什麼內容,而後 React 更新 DOM 以匹配 Clock 的渲染輸出。

  3. 當 Clock 的輸出插入到 DOM 中時,React 調用 componentDidMount() 生命週期鉤子。 在其中,Clock組件要求瀏覽器設置一個定時器,每秒鐘調用一次 tick()

  4. 瀏覽器每秒鐘調用 tick() 方法。 在其中,Clock 組件經過使用包含當前時間的對象調用 setState() 來調度UI更新。 經過調用 setState() ,React 知道狀態已經改變,並再次調用 render() 方法來肯定屏幕上應當顯示什麼。 這一次,render() 方法中的 this.state.date 將不一樣,因此渲染輸出將包含更新的時間,並相應地更新DOM。

  5. 一旦Clock組件被從DOM中移除,React會調用componentWillUnmount()這個鉤子函數,定時器也就會被清除。

4. 正確地使用狀態 

    關於 setState( ) 這裏有三件事情須要知道

4.1 不要直接更新狀態

//此代碼不會從新渲染組件:
this.state.comment = 'Hello';

//應當使用 setState():
this.setState({comment: 'Hello'});

    構造函數是惟一可以初始化 this.state 的地方。

4.2 狀態更新多是異步的

    React 能夠將多個setState() 調用合併成一個調用來提升性能。

    由於 this.props 和 this.state 多是異步更新的,你不該該依靠它們的值來計算下一個狀態。

//此代碼可能沒法更新計數器:
this.setState({
  counter: this.state.counter + this.props.increment,
});

//正確方法是,請使用第二種形式的 setState() 來接受一個函數而不是一個對象。 該函數將接收
//先前的狀態做爲第一個參數,將這次更新被應用時的props作爲第二個參數:
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

4.3 狀態更新合併

    當你調用 setState() 時,React 將你提供的對象合併到當前狀態。

    狀態可能包含一些獨立的變量:

constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

    能夠調用 setState()獨立更新他們:

componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }

    這裏的合併是淺合併,也就是說this.setState({comments})完整保留了this.state.posts,但徹底替換了this.state.comments

5. 數據自頂向下流動

    父組件或子組件都不能知道某個組件是有狀態仍是無狀態,而且它們不該該關心某組件是被定義爲一個函數仍是一個類。

    這就是爲何狀態一般被稱爲局部或封裝。 除了擁有並設置它的組件外,其它組件不可訪問。

    組件能夠選擇將其狀態做爲屬性傳遞給其子組件。

    這一般被稱爲 自頂向下 或 單向數據流。 任何狀態始終由某些特定組件全部,而且從該狀態導出的任何數據或 UI 只能影響樹中下方的組件。

相關文章
相關標籤/搜索