狀態(tài)和生命周期

學習使用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);

Try it on CodePen.

以上代碼忽略了一個關鍵的需求,就是設置定時器和每秒更新UI內(nèi)容。理想情況下技掏,我們希望只編寫一次代碼铃将,然后使用定時器來更新內(nèi)容。

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

如果想實現(xiàn)這個哑梳,我們需要在Clock的組件添加state劲阎。state是一個參數(shù),但是他是私有的并且由組件全權控制鸠真。

把函數(shù)轉換成類

舉個例子悯仙,可以把Clock組件轉換成類,只需要以下五步吠卷。

  • 1.創(chuàng)建一個同名的ES6類锡垄,并且使用extends React.Component.
  • 2.添加一個空的方法到render()里面。
  • 3.把函數(shù)的內(nèi)容放到render()方法里祭隔。
  • 4.替換render()方法里的參數(shù)名this.參數(shù)名
  • 5.刪除剩余的空函數(shù)聲明货岭。
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

Clock現(xiàn)在被定義成一個類。這樣我們就可以對組件添加額外的特性序攘,如當前狀態(tài)和生命周期茴她。

添加本地state到類中

date從參數(shù)到state只需要3步。

  • 1.在render()中替換this.參數(shù).datethis.state.date
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
  • 2.添加一個類構建方法到來創(chuàng)建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>
    );
  }
}

如何把對象傳給父類的構建器程奠,如:

  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

類組件會經(jīng)常調(diào)用父類構建的參數(shù)丈牢。

  • 3.在<Clock />元素中移除date
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

之后添加一個定時器,效果如下

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

Try it on CodePen.

之后添加個定時器就可以運作了瞄沙。

在類中添加一個生命周期方法

我們需要管理一個組件的生命周期己沛,尤其再不使用組建后,需要釋放使用的資源和空間距境。
Clock第一次渲染Dom的時候回在React中使用mounting方法申尼,釋放的時候會使用unmounting方法。我們可以在這兩個特殊的點里添加特有的方法垫桂。
如下

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

  componentDidMount() {
      //第一次啟動 如IOS的viewDidLoad
  }

  componentWillUnmount() {
    //釋放 如IOS的dealloc
  }
render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

這個方法就是生命周期师幕。

componentDidMount()這個方法會在組件輸出渲染dom后使用。這個時候可以設置一個定時器诬滩。

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

然后在組件釋放前霹粥,釋放不使用的定時器,如

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

最后需要實現(xiàn)tick()方法內(nèi)容疼鸟,來執(zhí)行定時器任務后控。
如下:

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

Try it on CodePen.

剖析上面的代碼流程。

  • 1.執(zhí)行ReactDOM.render()后會運行組件<Clock />空镜,運行后會調(diào)用構建函數(shù)constructor浩淘,就會初始化this.state對象并獲取當前時間捌朴。
  • 2.接著會運行組件<Clock />render()方法。由于React把組件的render()綁定了ReactDOM.render()张抄。所以誰輸出到界面上砂蔽。
  • 3.當組件<Clock />輸出顯示就會調(diào)用componentDidMount()創(chuàng)建定時器,并每秒執(zhí)行定時器里面的方法tick()欣鳖。
  • 4.在tick()方法中察皇,會設置this.state這個對象,并且獲取當前時間泽台,React會被告知狀態(tài)修改,并進行執(zhí)行render()矾缓。當render()執(zhí)行后怀酷,會通知ReactDOM.render并刷新。
  • 5.當把組件<Clock />移除會執(zhí)行componentWillUnmount并釋放定時器嗜闻。
    整個生命周期完畢蜕依。

使用當前的state

關于setState(),有三樣東西需要注意琉雳。

  • 不能直接賦值this.state
//錯誤的做法
this.state.comment = 'Hello';

需要使用

// Correct
this.setState({comment: 'Hello'});

只有在構建方法中才能直接賦值样眠。

  • state的更新盡可能異步進行
    React 為了性能,可能在一個的更新里批量處理多次的setState() 調(diào)用翠肘。
    因為this.propsthis.state可能異步更新了檐束,你不應該依賴他們的值來計算下一個state。
    如:
// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

以上做法錯誤的束倍,但是可以使用函數(shù)來解決這個問題被丧,如:

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

也可以寫成這樣,更佳規(guī)范

// Correct
this.setState(function(prevState, props) {
  return {
    counter: prevState.counter + props.increment
  };
});

State的更新是合并的

當執(zhí)行setState()绪妹,React會合并你提供的當前State到對象里甥桂。
例如,state包含了多個獨立的對象邮旷。

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

當你需要更新時黄选,可以對state里的對象分開回調(diào),如

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.

單項數(shù)據(jù)流

所有的父組件或者子組件都不知道一個組件是有狀態(tài)或者無狀態(tài)的,并且他們也不應該關心自己是被定義成一個函數(shù)或者是類組件狡孔。

這就是為什么state經(jīng)常被本地調(diào)用或者被封裝懂诗。對于別的組件來說,組件的擁有的state是不可被訪問的苗膝。

一個組件可能會把自己的state作為props傳遞給他們的子組件中:

這同樣適用用戶定義的組件中:

FormattedDate組件將會接收data作為他的props并且將不知道他是來自哪殃恒,是Clock's state植旧,是來自Clock's state, 還是來自手動輸入的离唐。

這就是我們平常所說的從上往下或者單向數(shù)據(jù)流病附。任何的state都是屬于一些特定的組件,并且任何的數(shù)據(jù)或者UI視圖 只能影響在他組件樹下面的的組件亥鬓。

如果你把一個組件的props想象成是瀑布完沪,每一個組件的state就像一個額外的水資源,并且這在任意點處鏈接還往下流嵌戈。

為了展示所有的組件都是孤立的覆积,我們創(chuàng)建一個App組件來渲染三個<Clock>組件:

每個Clock都會獨立設置以及更新自己的定時器。

在React app里熟呛,無論一個stateful or stateless的組件都被認為組件獨立的細節(jié)都可能隨著時間而改變宽档。

你能用stateless組件代替stateful組件,反之亦然庵朝。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吗冤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子九府,更是在濱河造成了極大的恐慌椎瘟,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侄旬,死亡現(xiàn)場離奇詭異肺蔚,居然都是意外死亡,警方通過查閱死者的電腦和手機勾怒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門婆排,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人笔链,你說我怎么就攤上這事段只。” “怎么了鉴扫?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵赞枕,是天一觀的道長。 經(jīng)常有香客問我坪创,道長炕婶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任莱预,我火速辦了婚禮涤久,結果婚禮上凌简,老公的妹妹穿的比我還像新娘别垮。我一直安慰自己,他們只是感情好枪狂,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宋渔,像睡著了一般州疾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上皇拣,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天严蓖,我揣著相機與錄音,去河邊找鬼氧急。 笑死颗胡,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的吩坝。 我是一名探鬼主播杭措,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼钾恢!你這毒婦竟也來了?” 一聲冷哼從身側響起鸳址,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤瘩蚪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后稿黍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疹瘦,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年巡球,在試婚紗的時候發(fā)現(xiàn)自己被綠了言沐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡酣栈,死狀恐怖险胰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情矿筝,我是刑警寧澤起便,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站窖维,受9級特大地震影響榆综,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铸史,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一鼻疮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧琳轿,春花似錦判沟、人聲如沸耿芹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽猩系。三九已至,卻和暖如春中燥,著一層夾襖步出監(jiān)牢的瞬間寇甸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工疗涉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拿霉,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓咱扣,卻偏偏與公主長得像绽淘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子闹伪,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • React版本:15.4.2**翻譯:xiyoki ** 考慮前一節(jié)中滴答作響的時鐘的例子沪铭。到目前為止,我們只學習...
    前端xiyoki閱讀 388評論 0 0
  • 想一下上一節(jié)中那個滴答計時的例子偏瓤。迄今為止杀怠,我們只學到一種更新UI的方法。我們通過調(diào)用ReactDOM.rende...
    莫銘閱讀 510評論 0 0
  • 考慮之前的例子厅克,我們只學會了一種方法去更新UI赔退,我們調(diào)用ReactDOM.render()去改變輸出渲染: 在這個...
    編碼的哲哲閱讀 573評論 0 0
  • State 和生命周期 考慮前面章節(jié)中時鐘的例子。 到目前位置证舟,我們僅學習了一種更新 UI 的方式硕旗。 我們調(diào)用Re...
    soojade閱讀 1,203評論 0 1
  • 【默默耕耘】20161127 day4 Sun. 今天進行第五首古詩背誦,學習從睜開眼睛的一刻就開始女责,一醒來漆枚,我就...
    ysmalina閱讀 153評論 0 0