React State(狀態(tài))

React 把組件看成是一個狀態(tài)機(jī)(State Machines)。通過與用戶的交互,實(shí)現(xiàn)不同狀態(tài),然后渲染 UI,讓用戶界面和數(shù)據(jù)保持一致。

React 里,只需更新組件的 state,然后根據(jù)新的 state 重新渲染用戶界面(不要操作 DOM)。

以下實(shí)例創(chuàng)建一個名稱擴(kuò)展為 React.Component 的 ES6 類,在 render() 方法中使用 this.state 來修改當(dāng)前的時間。

添加一個類構(gòu)造函數(shù)來初始化狀態(tài) this.state,類組件應(yīng)始終使用 props 調(diào)用基礎(chǔ)構(gòu)造函數(shù)。

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
 
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>現(xiàn)在是 {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
 
ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);

將生命周期方法添加到類中

在具有許多組件的應(yīng)用程序中,在銷毀時釋放組件所占用的資源非常重要。
每當(dāng) Clock 組件第一次加載到 DOM 中的時候,我們都想生成定時器,這在 React 中被稱為掛載。
同樣,每當(dāng) Clock 生成的這個 DOM 被移除的時候,我們也會想要清除定時器,這在 React 中被稱為卸載。
我們可以在組件類上聲明特殊的方法,當(dāng)組件掛載或卸載時,來運(yùn)行一些代碼:

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>現(xiàn)在是 {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
 
ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);
實(shí)例解析:

**componentDidMount() **與 componentWillUnmount() 方法被稱作生命周期鉤子。
在組件輸出到 DOM 后會執(zhí)行 componentDidMount() 鉤子,我們就可以在這個鉤子上設(shè)置一個定時器。
this.timerID 為計算器的 ID,我們可以在 componentWillUnmount() 鉤子中卸載計算器。

代碼執(zhí)行順序:
  1. 當(dāng) <Clock /> 被傳遞給 ReactDOM.render() 時,React 調(diào)用 Clock 組件的構(gòu)造函數(shù)。 由于 Clock 需要顯示當(dāng)前時間,所以使用包含當(dāng)前時間的對象來初始化 this.state 。 我們稍后會更新此狀態(tài)。
  2. React 然后調(diào)用 Clock 組件的 render() 方法。這是 React 了解屏幕上應(yīng)該顯示什么內(nèi)容,然后 React 更新 DOM 以匹配 Clock 的渲染輸出。
  3. 當(dāng) Clock 的輸出插入到 DOM 中時,React 調(diào)用 componentDidMount() 生命周期鉤子。 在其中,Clock 組件要求瀏覽器設(shè)置一個定時器,每秒鐘調(diào)用一次 tick()。
  4. 瀏覽器每秒鐘調(diào)用 tick() 方法。 在其中,Clock 組件通過使用包含當(dāng)前時間的對象調(diào)用 setState() 來調(diào)度UI更新。 通過調(diào)用 setState() ,React 知道狀態(tài)已經(jīng)改變,并再次調(diào)用 render() 方法來確定屏幕上應(yīng)當(dāng)顯示什么。 這一次,render() 方法中的 this.state.date 將不同,所以渲染輸出將包含更新的時間,并相應(yīng)地更新 DOM。
  5. 一旦 Clock 組件被從 DOM 中移除,React 會調(diào)用 componentWillUnmount() 這個鉤子函數(shù),定時器也就會被清除。
數(shù)據(jù)自頂向下流動

父組件或子組件都不能知道某個組件是有狀態(tài)還是無狀態(tài),并且它們不應(yīng)該關(guān)心某組件是被定義為一個函數(shù)還是一個類。

這就是為什么狀態(tài)通常被稱為局部或封裝。 除了擁有并設(shè)置它的組件外,其它組件不可訪問。

以下實(shí)例中 FormattedDate 組件將在其屬性中接收到 date 值,并且不知道它是來自 Clock 狀態(tài)、還是來自 Clock 的屬性、亦或手工輸入:

function FormattedDate(props) {
  return <h2>現(xiàn)在是 {props.date.toLocaleTimeString()}.</h2>;
}
 
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>
        <FormattedDate date={this.state.date} />
      </div>
    );
  }
}
 
ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);

這通常被稱為自頂向下或單向數(shù)據(jù)流。 任何狀態(tài)始終由某些特定組件所有,并且從該狀態(tài)導(dǎo)出的任何數(shù)據(jù)或 UI 只能影響樹中下方的組件。
如果你想象一個組件樹作為屬性的瀑布,每個組件的狀態(tài)就像一個額外的水源,它連接在一個任意點(diǎn),但也流下來。
為了表明所有組件都是真正隔離的,我們可以創(chuàng)建一個 App 組件,它渲染三個Clock:

function FormattedDate(props) {
  return <h2>現(xiàn)在是 {props.date.toLocaleTimeString()}.</h2>;
}
 
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>
        <FormattedDate date={this.state.date} />
      </div>
    );
  }
}
 
function App() {
  return (
    <div>
      <Clock />
      <Clock />
      <Clock />
    </div>
  );
}
 
ReactDOM.render(<App />, document.getElementById('example'));

以上實(shí)例中每個 Clock 組件都建立了自己的定時器并且獨(dú)立更新。
在 React 應(yīng)用程序中,組件是有狀態(tài)還是無狀態(tài)被認(rèn)為是可能隨時間而變化的組件的實(shí)現(xiàn)細(xì)節(jié)。
我們可以在有狀態(tài)組件中使用無狀態(tài)組件,也可以在無狀態(tài)組件中使用有狀態(tài)組件。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容