React學(xué)習(xí) —— 受控組件隆嗅、生命周期界阁、PureComponent

受控組件與非受控組件

受控組件:

在 HTML 中,表單元素(如<input>胖喳、 <textarea><select>)之類的表單元素通常自己維護(hù) state泡躯,并根據(jù)用戶輸入進(jìn)行更新。而在 React 中,可變狀態(tài)(mutable state)通常保存在組件的 state 屬性中较剃,并且只能通過使用 setState()來更新咕别。

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('提交的名字: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          名字:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}

該組件實(shí)現(xiàn)了一個(gè)點(diǎn)擊提交,打印名字的功能写穴。
有時(shí)使用受控組件會(huì)很麻煩惰拱,因?yàn)槟阈枰獮閿?shù)據(jù)變化的每種方式都編寫事件處理函數(shù)(因?yàn)閿?shù)據(jù)都存在state里,所以需要編寫事件處理函數(shù)更新state啊送,就比如這里都handleChange)偿短,并通過一個(gè) React 組件傳遞所有的輸入 state。

非受控組件

要編寫一個(gè)非受控組件删掀,而不是為每個(gè)狀態(tài)更新都編寫數(shù)據(jù)處理函數(shù)翔冀,你可以 使用 ref 來從 DOM 節(jié)點(diǎn)中獲取表單數(shù)據(jù)导街。

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.input = React.createRef();
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.input.current.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" ref={this.input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

這里和受控組件都區(qū)別就在于披泪,我們并沒有給input賦值(value={this.state.xxx}),數(shù)據(jù)本身都是存儲(chǔ)在dom節(jié)點(diǎn)本身的搬瑰,每次我們需要獲取或者改變的時(shí)候我們應(yīng)該直接去通過ref操作dom節(jié)點(diǎn)款票,而非設(shè)置state。

默認(rèn)值

如果是受控組件泽论,value就可以充當(dāng)默認(rèn)值艾少,而非受控組件由于沒有可以傳遞的地方本應(yīng)該是除了直接操作dom之外沒有設(shè)置默認(rèn)值的方法的,但是react提供了封裝翼悴,我們可以在dom上添加default值:

render() {
  return (
    <form onSubmit={this.handleSubmit}>
      <label>
        Name:
        <input
          defaultValue="Bob"
          type="text"
          ref={this.input} />
      </label>
      <input type="submit" value="Submit" />
    </form>
  );
}

生命周期

常用的生命周期方法

本節(jié)中的方法涵蓋了創(chuàng)建 React 組件時(shí)能遇到的絕大多數(shù)用例缚够。想要更好了解這些方法,可以參考生命周期圖譜鹦赎。

render()

只能返回:React谍椅、fragments、Portals古话、字符串或者數(shù)值雏吭、布爾類型或 null。

constructor()

通常陪踩,在 React 中杖们,構(gòu)造函數(shù)僅用于以下兩種情況:

  • 通過給 this.state 賦值對(duì)象來初始化內(nèi)部 state
  • 事件處理函數(shù)綁定實(shí)例
    如果不做這些處理肩狂,則不需要constructor()
    避免將 props 的值復(fù)制給 state摘完!這是一個(gè)常見的錯(cuò)誤!傻谁!
constructor(props) {
 super(props);
 // 不要這樣做
 this.state = { color: props.color };
}

componentDidMount()

會(huì)在組件掛載后(插入 DOM 樹中)立即調(diào)用孝治。
這個(gè)方法是比較適合添加訂閱的地方。如果添加了訂閱,請(qǐng)不要忘記在 componentWillUnmount() 里取消訂閱荆秦。

你可以在 componentDidMount() 里可以直接調(diào)用 setState()篱竭。它將觸發(fā)額外渲染,但此渲染會(huì)發(fā)生在瀏覽器更新屏幕之前步绸。如此保證了即使在 render() 兩次調(diào)用的情況下掺逼,用戶也不會(huì)看到中間狀態(tài)。請(qǐng)謹(jǐn)慎使用該模式瓤介,因?yàn)樗鼤?huì)導(dǎo)致性能問題吕喘。通常,你應(yīng)該在 constructor() 中初始化 state刑桑。如果你的渲染依賴于 DOM 節(jié)點(diǎn)的大小或位置氯质,比如實(shí)現(xiàn) modals 和 tooltips 等情況下,你可以使用此方式處理

componentDidUpdate()

componentDidUpdate(prevProps, prevState, snapshot)

componentDidUpdate() 會(huì)在更新后會(huì)被立即調(diào)用祠斧。首次渲染不會(huì)執(zhí)行此方法闻察。
當(dāng)組件更新后,可以在此處對(duì) DOM 進(jìn)行操作琢锋。如果你對(duì)更新前后的 props 進(jìn)行了比較辕漂,也可以選擇在此處進(jìn)行網(wǎng)絡(luò)請(qǐng)求。(例如吴超,當(dāng) props 未發(fā)生變化時(shí)钉嘹,則不會(huì)執(zhí)行網(wǎng)絡(luò)請(qǐng)求)。

componentWillUnmount()

componentWillUnmount() 會(huì)在組件卸載及銷毀之前直接調(diào)用鲸阻。在此方法中執(zhí)行必要的清理操作跋涣,例如,清除 timer鸟悴,取消網(wǎng)絡(luò)請(qǐng)求或清除在 componentDidMount() 中創(chuàng)建的訂閱等陈辱。
componentWillUnmount() 中不應(yīng)調(diào)用 setState(),因?yàn)樵摻M件將永遠(yuǎn)不會(huì)重新渲染遣臼。組件實(shí)例卸載后性置,將永遠(yuǎn)不會(huì)再掛載它。

shouldComponentUpdate()

當(dāng) props 或 state 發(fā)生變化時(shí)揍堰,shouldComponentUpdate() 會(huì)在渲染執(zhí)行之前被調(diào)用鹏浅。返回值默認(rèn)為 true。首次渲染或使用 forceUpdate() 時(shí)不會(huì)調(diào)用該方法屏歹。
此方法僅作為性能優(yōu)化的方式而存在隐砸。不要企圖依靠此方法來“阻止”渲染,因?yàn)檫@可能會(huì)產(chǎn)生 bug蝙眶。

我們不建議在 shouldComponentUpdate() 中進(jìn)行深層比較或使用 JSON.stringify()季希。這樣非常影響效率褪那,且會(huì)損害性能。

其他API

setState()

setState(updater[, callback])

將 setState() 視為請(qǐng)求而不是立即更新組件的命令式塌。為了更好的感知性能博敬,React 會(huì)延遲調(diào)用它,然后通過一次傳遞更新多個(gè)組件峰尝。React 并不會(huì)保證 state 的變更會(huì)立即生效偏窝。
setState() 并不總是立即更新組件。它會(huì)批量推遲更新武学。這使得在調(diào)用 setState() 后立即讀取 this.state 成為了隱患祭往。為了消除隱患,請(qǐng)使用 componentDidUpdate 或者 setState 的回調(diào)函數(shù)(setState(updater, callback))火窒,這兩種方式都可以保證在應(yīng)用更新后觸發(fā)硼补。如需基于之前的 state 來設(shè)置當(dāng)前的 state,請(qǐng)閱讀下述關(guān)于參數(shù) updater 的內(nèi)容熏矿。

this.setState((state, props) => {
  return {counter: state.counter + props.step};
});

updater 函數(shù)中接收的 state 和 props 都保證為最新已骇。updater 的返回值會(huì)與 state 進(jìn)行淺合并。
有關(guān)更多詳細(xì)信息曲掰,請(qǐng)參閱:

forceUpdate()

默認(rèn)情況下栏妖,當(dāng)組件的 state 或 props 發(fā)生變化時(shí),組件將重新渲染奖恰。如果 render() 方法依賴于其他數(shù)據(jù)吊趾,則可以調(diào)用 forceUpdate() 強(qiáng)制讓組件重新渲染。
調(diào)用 forceUpdate() 將致使組件調(diào)用 render() 方法瑟啃,此操作會(huì)跳過該組件的 shouldComponentUpdate()论泛。

ReactDOM

react-dom 的 package 提供了可在應(yīng)用頂層使用的 DOM(DOM-specific)方法,如果有需要蛹屿,你可以把這些方法用于 React 模型以外的地方屁奏。不過一般情況下,大部分組件都不需要使用這個(gè)模塊错负。

React.Component與React.PureComponent

React.PureComponentReact.Component 很相似坟瓢。兩者的區(qū)別在于 React.Component 并未實(shí)現(xiàn) shouldComponentUpdate(),而 React.PureComponent 中以淺層對(duì)比 prop 和 state 的方式來實(shí)現(xiàn)了該函數(shù)犹撒。

shouldComponentUpdate在剛剛的生命周期中也說過折联,當(dāng)props或者state發(fā)生變化時(shí),shouldComponentUpdate() 會(huì)在渲染執(zhí)行之前被調(diào)用识颊。
返回默認(rèn)值true诚镰,首次渲染和 forceUpdate() 時(shí)不會(huì)調(diào)用該方法。

如果 shouldComponentUpdate() 返回 false,則不會(huì)調(diào)用 UNSAFE_componentWillUpdate()清笨,render()componentDidUpdate()月杉。
而React.Component的shouldComponentUpdate默認(rèn)就是返回true的,React.PureComponent是實(shí)現(xiàn)一套邏輯抠艾,淺比較props和state沙合,并減少了跳過必要更新的可能性。

什么是淺比較跌帐?
對(duì)于基本類型(primitives)首懈,例如數(shù)字或者布爾值,來說谨敛,淺拷貝將會(huì)檢查其值是否相同究履,例如1與1相等,true與true相等脸狸。對(duì)于引用類型的變量最仑,例如復(fù)雜的javascript對(duì)象或者數(shù)組,來說炊甲,淺拷貝將僅僅檢查它們的引用值是否相等泥彤。這意味著,對(duì)于引用類型的變量來說卿啡,如果我們只是更新了其中的一個(gè)元素吟吝,例如更新了數(shù)組中某一位置的值,那么更新前后的數(shù)組仍是相等的颈娜。

因此意味著相比于Component剑逃,PureCompoent的性能表現(xiàn)將會(huì)更好。但使用PureCompoent要求滿足如下條件:

  • props和state都不可變
  • props和state沒有層級(jí)
  • 如果數(shù)據(jù)改變無(wú)法反應(yīng)在淺拷貝上官辽,應(yīng)該調(diào)用forceUpdate更新蛹磺。

React.PureComponent 中的 shouldComponentUpdate() 僅作對(duì)象的淺層比較。如果對(duì)象中包含復(fù)雜的數(shù)據(jù)結(jié)構(gòu)同仆,則有可能因?yàn)闊o(wú)法檢查深層的差別萤捆,產(chǎn)生錯(cuò)誤的比對(duì)結(jié)果。僅在你的 props 和 state 較為簡(jiǎn)單時(shí)俗批,才使用 React.PureComponent俗或,或者在深層數(shù)據(jù)結(jié)構(gòu)發(fā)生變化時(shí)調(diào)用 forceUpdate() 來確保組件被正確地更新。

參考文獻(xiàn)

https://react.docschina.org/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扶镀,一起剝皮案震驚了整個(gè)濱河市蕴侣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌臭觉,老刑警劉巖昆雀,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辱志,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡狞膘,警方通過查閱死者的電腦和手機(jī)揩懒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挽封,“玉大人已球,你說我怎么就攤上這事「ㄔ福” “怎么了智亮?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)点待。 經(jīng)常有香客問我阔蛉,道長(zhǎng),這世上最難降的妖魔是什么癞埠? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任状原,我火速辦了婚禮,結(jié)果婚禮上苗踪,老公的妹妹穿的比我還像新娘颠区。我一直安慰自己,他們只是感情好通铲,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布毕莱。 她就那樣靜靜地躺著,像睡著了一般测暗。 火紅的嫁衣襯著肌膚如雪央串。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天碗啄,我揣著相機(jī)與錄音,去河邊找鬼稳摄。 笑死稚字,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的厦酬。 我是一名探鬼主播胆描,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼仗阅!你這毒婦竟也來了昌讲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤减噪,失蹤者是張志新(化名)和其女友劉穎短绸,沒想到半個(gè)月后车吹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡醋闭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年窄驹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片证逻。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡乐埠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出囚企,到底是詐尸還是另有隱情丈咐,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布龙宏,位于F島的核電站棵逊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏烦衣。R本人自食惡果不足惜歹河,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望花吟。 院中可真熱鬧秸歧,春花似錦、人聲如沸衅澈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)今布。三九已至经备,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間部默,已是汗流浹背侵蒙。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留傅蹂,地道東北人纷闺。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像份蝴,于是被迫代替她去往敵國(guó)和親犁功。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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

  • 作為一個(gè)合格的開發(fā)者婚夫,不要只滿足于編寫了可以運(yùn)行的代碼浸卦。而要了解代碼背后的工作原理;不要只滿足于自己的程序...
    六個(gè)周閱讀 8,422評(píng)論 1 33
  • 生命周期流程圖簡(jiǎn)單如下: 組件讓你把用戶界面分成獨(dú)立的案糙,可重復(fù)使用的部分限嫌,并且將每個(gè)部分分開考慮靴庆。React.Co...
    Simple_Learn閱讀 1,072評(píng)論 0 0
  • 說在前面 關(guān)于 react 的總結(jié)過去半年就一直碎碎念著要搞起來,各(wo)種(tai)原(lan)因(le)萤皂。心...
    陳嘻嘻啊閱讀 6,846評(píng)論 7 41
  • 40撒穷、React 什么是React?React 是一個(gè)用于構(gòu)建用戶界面的框架(采用的是MVC模式):集中處理VIE...
    萌妹撒閱讀 1,005評(píng)論 0 1
  • 安裝: 概述 React起源于FaceBook的內(nèi)部項(xiàng)目,因?yàn)樵摴緦?duì)市場(chǎng)上所有的JavaScript MVC框架...
    姒沝無(wú)痕閱讀 709評(píng)論 0 0