state和props

state

state 是私有的,并且完全受控于當(dāng)前組件。class組件才有state。

將函數(shù)組件轉(zhuǎn)化成class組件

function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}
#轉(zhuǎn)化為class組件
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
  1. 創(chuàng)建一個與函數(shù)同名的類并且繼承于 React.Component
  2. 添加一個空的 render() 方法, 將函數(shù)體移動到 render() 方法之中。
  3. render() 方法中使用 this.props 替換 props。

每次組件更新時 render 方法都會被調(diào)用,但只要在相同的 DOM 節(jié)點(diǎn)中渲染 <Clock /> ,就僅有一個 Clock 組件的 class 實例被創(chuàng)建使用。這就使得我們可以使用如 state 或生命周期方法等很多其他特性。

在class組件中添加局部state

class Clock extends React.Component {
  constructor(props) {
    #Class 組件應(yīng)該始終使用 props 參數(shù)來調(diào)用父類的構(gòu)造函數(shù)。
    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')
);

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

在具有許多組件的應(yīng)用程序中,當(dāng)組件被銷毀時釋放所占用的資源是非常重要的。

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

  componentDidMount() {
    #當(dāng) `Clock` 組件第一次被渲染到 DOM 中的時候,就為其設(shè)置一個計時器。
    #這在 React 中被稱為“掛載(mount)”。
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    #當(dāng) DOM 中 `Clock` 組件被刪除的時候,應(yīng)該清除計時器。
    #這在 React 中被稱為“卸載(unmount)”。
    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>
    );
  }
}

執(zhí)行順序:

  1. 當(dāng) <Clock /> 被傳給 ReactDOM.render()的時候,React 會調(diào)用 Clock 組件的構(gòu)造函數(shù)。因為 Clock 需要顯示當(dāng)前的時間,所以它會用一個包含當(dāng)前時間的對象來初始化 this.state。我們會在之后更新 state。
  2. 之后 React 會調(diào)用組件的 render() 方法。這就是 React 確定該在頁面上展示什么的方式。然后 React 更新 DOM 來匹配 Clock 渲染的輸出。
  3. 當(dāng) Clock 的輸出被插入到 DOM 中后,React 就會調(diào)用 ComponentDidMount() 生命周期方法。在這個方法中,Clock 組件向瀏覽器請求設(shè)置一個計時器來每秒調(diào)用一次組件的 tick() 方法。
  4. 瀏覽器每秒都會調(diào)用一次 tick() 方法。 在這方法之中,Clock 組件會通過調(diào)用 setState() 來計劃進(jìn)行一次 UI 更新。得益于 setState() 的調(diào)用,React 能夠知道 state 已經(jīng)改變了,然后會重新調(diào)用 render() 方法來確定頁面上該顯示什么。這一次,render() 方法中的 this.state.date 就不一樣了,如此以來就會渲染輸出更新過的時間。React 也會相應(yīng)的更新 DOM。
  5. 一旦 Clock 組件從 DOM 中被移除,React 就會調(diào)用 componentWillUnmount() 生命周期方法,這樣計時器就停止了。

State的使用

  • 不要直接修改 State
this.state.comment = 'Hello'; // Wrong
#應(yīng)該使用 setState():
this.setState({comment: 'Hello'}); // Correct
  • State 的更新可能是異步的

出于性能考慮,React 可能會把多個 setState() 調(diào)用合并成一個調(diào)用。因為 this.props 和 this.state 可能會異步更新,所以你不要依賴他們的值來更新下一個狀態(tài)。

this.setState({
  counter: this.state.counter + this.props.increment,
}); // Wrong
#要解決這個問題,可以讓 setState() 接收一個函數(shù)而不是一個對象。這個函數(shù)用上一個 state 作為第一個參數(shù),將此次更新被應(yīng)用時的 props 做為第二個參數(shù):
this.setState((state, props) => ({
  counter: state.counter + props.increment
})); // Correct
  • State 的更新會被合并

調(diào)用 setState() 的時候,React 會把你提供的對象合并到當(dāng)前的 state。這里的合并是淺合并。

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

  componentDidMount() {
    # 可以分別調(diào)用 setState() 來單獨(dú)地更新它們
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

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

數(shù)據(jù)是自頂向下流動的

父組件或子組件都不能知道某個組件是有狀態(tài)還是無狀態(tài),并且它們不應(yīng)該關(guān)心某組件是被定義為一個函數(shù)還是一個class。
這就是為什么state通常被稱為局部或封裝。 除了擁有并設(shè)置它的組件外,其它組件不可訪問。

組件可以選擇把它的 state 作為 props 向下傳遞到它的子組件中。但子組件本身無法知道它是來自于父組件的 state、props、還是手動輸入的。

這通常被稱為“自頂向下”或“單向”數(shù)據(jù)流。 任何狀態(tài)始終由某些特定組件所有,并且從該狀態(tài)導(dǎo)出的任何數(shù)據(jù)或 UI 只能影響樹中下方的組件。

props

state 和 props 主要的區(qū)別在于 props 是不可變的,而 state 可以根據(jù)與用戶交互來改變。

  • props 驗證

props 驗證使用 propTypes,它可以保證我們的應(yīng)用組件被正確使用,React.PropTypes 提供很多驗證器 (validator) 來驗證傳入數(shù)據(jù)是否有效。當(dāng)向 props 傳入無效數(shù)據(jù)時,JavaScript 控制臺會拋出警告。

let title = "測試";
// let title = 123;
class TestTitle extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.title}</h1>
    );
  }
}
 #當(dāng)title不是string時(123),拋出警告。
TestTitle.propTypes = {
  title: PropTypes.string
};

ReactDOM.render(
    <TestTitle title={title} />,
    document.getElementById('root')
);
最后編輯于
?著作權(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)容