欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談使用React.setState需要注意的三點(diǎn)

 更新時(shí)間:2017年12月18日 11:37:00   作者:little_ab  
本篇文章主要介紹了淺談使用React.setState需要注意的三點(diǎn),提出了三點(diǎn)對(duì) React 新手來說是很容易忽略的地方,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

前言

這篇文章原標(biāo)題是 3 Reasons why I stopped using React.setState ,但是我對(duì)原文作者提出的論點(diǎn)不是很感冒,但是作者提出的三點(diǎn)對(duì) React 新手來說是很容易忽略的地方,所以我在這里只提出部分內(nèi)容,而且把標(biāo)題改為 使用React.setState需要注意的三點(diǎn) 。

正文

對(duì) React 新手來說,使用 setState 是一件很復(fù)雜的事情。即使是熟練的 React 開發(fā),也很有可能因?yàn)?React 的一些機(jī)制而產(chǎn)生一些bug,比如下面這個(gè)例子:

文檔 中也說明了當(dāng)使用 setState 的時(shí)候,需要注意什么問題:

注意:

絕對(duì)不要 直接改變 this.state ,因?yàn)橹笳{(diào)用 setState() 可能會(huì)替換掉你做的改

變。把 this.state 當(dāng)做是不可變的。

setState() 不會(huì)立刻改變 this.state ,而是創(chuàng)建一個(gè)即將處理的 state 轉(zhuǎn)變。在調(diào)用該方法之后訪問 this.state 可能會(huì)返回現(xiàn)有的值。

對(duì) setState 的調(diào)用沒有任何同步性的保證,并且調(diào)用可能會(huì)為了性能收益批量執(zhí)行。

setState() 將總是觸發(fā)一次重繪,除非在 shouldComponentUpdate() 中實(shí)現(xiàn)了條件渲染邏輯。如果可變對(duì)象被使用了,但又不能在 shouldComponentUpdate() 中實(shí)現(xiàn)這種邏輯,僅在新 state 和之前的 state 存在差異的時(shí)候調(diào)用 setState() 可以避免不必要的重新渲染。

總結(jié)出來,當(dāng)使用 setState 的時(shí)候,有三個(gè)問題需要注意:

1. setState是異步的(譯者注:不保證同步的)

很多開發(fā)剛開始沒有注意到 setState 是異步的。如果你修改一些 state ,然后直接查看它,你會(huì)看到之前的 state 。這是 setState 中最容易出錯(cuò)的地方。 setState 這個(gè)詞看起來并不像是異步的,所以如果你不假思索的用它,可能會(huì)造成 bugs 。下面這個(gè)例子很好的展示了這個(gè)問題:

class Select extends React.Component {
 constructor(props, context) {
  super(props, context)
  this.state = {
   selection: props.values[0]
  };
 }
 
 render() {
  return (
   <ul onKeyDown={this.onKeyDown} tabIndex={0}>
    {this.props.values.map(value =>
     <li
      className={value === this.state.selection ? 'selected' : ''}
      key={value}
      onClick={() => this.onSelect(value)}
     >
      {value}
     </li> 
    )} 
   </ul>
  )
 }
 
 onSelect(value) {
  this.setState({
   selection: value
  })
  this.fireOnSelect()
 }

 onKeyDown = (e) => {
  const {values} = this.props
  const idx = values.indexOf(this.state.selection)
  if (e.keyCode === 38 && idx > 0) { /* up */
   this.setState({
    selection: values[idx - 1]
   })
  } else if (e.keyCode === 40 && idx < values.length -1) { /* down */
   this.setState({
    selection: values[idx + 1]
   }) 
  }
  this.fireOnSelect()
 }
  
 fireOnSelect() {
  if (typeof this.props.onSelect === "function")
   this.props.onSelect(this.state.selection) /* not what you expected..*/
 }
}

ReactDOM.render(
 <Select 
  values={["State.", "Should.", "Be.", "Synchronous."]} 
  onSelect={value => console.log(value)}
 />,
 document.getElementById("app")
)

第一眼看上去,這個(gè)代碼似乎沒有什么問題。兩個(gè)事件處理中調(diào)用 onSelect 方法。但是,這個(gè) Select 組件中有一個(gè) bug 很好的展現(xiàn)了之前的 GIF 圖。 onSelect 方法永遠(yuǎn)傳遞的是之前的 state.selection 值,因?yàn)楫?dāng) fireOnSelect 調(diào)用的時(shí)候, setState 還沒有完成它的工作。我認(rèn)為 React 至少要把 setState 改名為 scheduleState 或者把回掉函數(shù)設(shè)為必須參數(shù)。

這個(gè)bug很容易修改,最難的地方在于你要知道有這個(gè)問題。

2. setState會(huì)造成不必要的渲染

setState 造成的第二個(gè)問題是:每次調(diào)用都會(huì)造成重新渲染。很多時(shí)候,這些重新渲染是不必要的。你可以用 React performance tools 中的 printWasted 來查看什么時(shí)候會(huì)發(fā)生不必要渲染。但是,大概的說,不必要的渲染有以下幾個(gè)原因:

  1. 新的 state 其實(shí)和之前的是一樣的。這個(gè)問題通??梢酝ㄟ^ shouldComponentUpdate 來解決。也可以用 pure render 或者其他的庫賴解決這個(gè)問題。
  2. 通常發(fā)生改變的 state 是和渲染有關(guān)的,但是也有例外。比如,有些數(shù)據(jù)是根據(jù)某些狀態(tài)來顯示的。
  3. 第三,有些 state 和渲染一點(diǎn)關(guān)系都沒有。有一些 state 可能是和事件、 timer ID 有關(guān)的。

3.setState并不能很有效的管理所有的組件狀態(tài)

基于上面的最后一條,并不是所有的組件狀態(tài)都應(yīng)該用 setState 來進(jìn)行保存和更新的。復(fù)雜的組件可能會(huì)有各種各樣的狀態(tài)需要管理。用 setState 來管理這些狀態(tài)不但會(huì)造成很多不需要的重新渲染,也會(huì)造成相關(guān)的生命周期鉤子一直被調(diào)用,從而造成很多奇怪的問題。

后話

在原文中作者推薦了一個(gè)叫做 MobX 的庫來管理部分狀態(tài),我不是很感冒,所以我就不介紹。如果感興趣的,可以通過最上面的鏈接看看原文中的介紹。

基于上面提出的三點(diǎn),我認(rèn)為新手應(yīng)該注意的地方是:

setState 是不保證同步的

setState 是不保證同步的,是不保證同步的,是不保證同步的。重要的事情說三遍。之所以不說它是異步的,是因?yàn)?setState 在某些情況下也是同步更新的。 可以參考這篇文章

如果需要在 setState 后直接獲取修改后的值,那么有幾個(gè)方案:

傳入對(duì)應(yīng)的參數(shù),不通過 this.state 獲取

針對(duì)于之前的例子,完全可以在調(diào)用 fireOnSelect 的時(shí)候,傳入需要的值。而不是在方法中在通過 this.state 來獲取

使用回調(diào)函數(shù)

setState 方法接收一個(gè) function 作為回調(diào)函數(shù)。這個(gè)回掉函數(shù)會(huì)在 setState 完成以后直接調(diào)用,這樣就可以獲取最新的 state 。對(duì)于之前的例子,就可以這樣:

this.setState({
 selection: value
}, this.fireOnSelect)

使用setTimeout

在 setState 使用 setTimeout 來讓 setState 先完成以后再執(zhí)行里面內(nèi)容。這樣子:

this.setState({
 selection: value
});
setTimeout(this.fireOnSelect, 0);

直接輸出,回調(diào)函數(shù), setTimeout 對(duì)比

componentDidMount(){
  this.setState({val: this.state.val + 1}, ()=>{
   console.log("In callback " + this.state.val);
  });

  console.log("Direct call " + this.state.val);  
  setTimeout(()=>{
   console.log("begin of setTimeout" + this.state.val);
    this.setState({val: this.state.val + 1}, ()=>{
     console.log("setTimeout setState callback " + this.state.val);
    });

   setTimeout(()=>{
    console.log("setTimeout of settimeout " + this.state.val);
   }, 0);

   console.log("end of setTimeout " + this.state.val);
  }, 0);
 }

如果val默認(rèn)為0, 輸入的結(jié)果是:

Direct call 0
In callback 1
begin of setTimeout 1
setTimeout setState callback 2
end of setTimeout 2
setTimeout of settimeout 2

和渲染無關(guān)的狀態(tài)盡量不要放在 state 中來管理

通常 state 中只來管理和渲染有關(guān)的狀態(tài) ,從而保證 setState 改變的狀態(tài)都是和渲染有關(guān)的狀態(tài)。這樣子就可以避免不必要的重復(fù)渲染。其他和渲染無關(guān)的狀態(tài),可以直接以屬性的形式保存在組件中,在需要的時(shí)候調(diào)用和改變,不會(huì)造成渲染。

避免不必要的修改,當(dāng) state 的值沒有發(fā)生改變的時(shí)候,盡量不要使用 setState 。雖然 shouldComponentUpdate 和 PureComponent 可以避免不必要的重復(fù)渲染,但是還是增加了一層 shallowEqual 的調(diào)用,造成多余的浪費(fèi)。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解在React里使用

    詳解在React里使用"Vuex"

    本篇文章主要介紹了詳解在React里使用"Vuex",小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • 用React實(shí)現(xiàn)一個(gè)完整的TodoList的示例代碼

    用React實(shí)現(xiàn)一個(gè)完整的TodoList的示例代碼

    本篇文章主要介紹了用React實(shí)現(xiàn)一個(gè)完整的TodoList的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • React樣式?jīng)_突解決問題的方法

    React樣式?jīng)_突解決問題的方法

    本文主要介紹了React樣式?jīng)_突解決問題的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • ReactRouter的實(shí)現(xiàn)方法

    ReactRouter的實(shí)現(xiàn)方法

    這篇文章主要介紹了ReactRouter的實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • 詳解React之父子組件傳遞和其它一些要點(diǎn)

    詳解React之父子組件傳遞和其它一些要點(diǎn)

    這篇文章主要介紹了詳解React之父子組件傳遞和其它一些要點(diǎn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-06-06
  • 使用React+ts實(shí)現(xiàn)無縫滾動(dòng)的走馬燈詳細(xì)過程

    使用React+ts實(shí)現(xiàn)無縫滾動(dòng)的走馬燈詳細(xì)過程

    這篇文章主要給大家介紹了關(guān)于使用React+ts實(shí)現(xiàn)無縫滾動(dòng)的走馬燈詳細(xì)過程,文中給出了詳細(xì)的代碼示例以及圖文教程,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-08-08
  • react-router-dom6(對(duì)比?router5)快速入門指南

    react-router-dom6(對(duì)比?router5)快速入門指南

    這篇文章主要介紹了快速上手react-router-dom6(對(duì)比?router5),通過本文學(xué)習(xí)最新的react-router-dom?v6版本的路由知識(shí),并且會(huì)與v5老版本進(jìn)行一些對(duì)比,需要的朋友可以參考下
    2022-08-08
  • Shopee在React?Native?架構(gòu)方面的探索及發(fā)展歷程

    Shopee在React?Native?架構(gòu)方面的探索及發(fā)展歷程

    這篇文章主要介紹了Shopee在React?Native?架構(gòu)方面的探索,本文會(huì)從發(fā)展歷史、架構(gòu)模型、系統(tǒng)設(shè)計(jì)、遷移方案四個(gè)方向逐一介紹我們?nèi)绾我徊讲降貪M足多團(tuán)隊(duì)在復(fù)雜業(yè)務(wù)中的開發(fā)需求,需要的朋友可以參考下
    2022-07-07
  • React Router 5.1.0使用useHistory做頁面跳轉(zhuǎn)導(dǎo)航的實(shí)現(xiàn)

    React Router 5.1.0使用useHistory做頁面跳轉(zhuǎn)導(dǎo)航的實(shí)現(xiàn)

    本文主要介紹了React Router 5.1.0使用useHistory做頁面跳轉(zhuǎn)導(dǎo)航的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • React?正確使用useCallback?useMemo的方式

    React?正確使用useCallback?useMemo的方式

    這篇文章主要介紹了React?正確使用useCallback?useMemo的方式,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-08-08

最新評(píng)論