成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

React 新特性 Hooks 講解及實(shí)例(二)

zero / 2801人閱讀

摘要:還可以返回另一個(gè)回調(diào)函數(shù),這個(gè)函數(shù)的執(zhí)行時(shí)機(jī)很重要。對(duì)于第二個(gè)我們可以通過(guò)返回一個(gè)回調(diào)函數(shù)來(lái)注銷事件的注冊(cè)。回調(diào)函數(shù)在視圖被銷毀之前觸發(fā),銷毀的原因有兩種重新渲染和組件卸載。

本文是 React 系列的第二篇

React 新特性講解及實(shí)例(一)

想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你!

什么是 Hooks

Hook 是 React 16.8 的新增特性。它可以讓你在不編寫(xiě) 類組件 的情況下使用 state 以及其他的 React 特性。

類組件的不足

狀態(tài)邏輯復(fù)用難

缺少?gòu)?fù)用機(jī)制

渲染屬性和高階組件導(dǎo)致層級(jí)冗余

趨向復(fù)雜難以維護(hù)

生命周期函數(shù)混雜不相干邏輯

相干邏輯分散在不同生命周期

this 指向困擾

內(nèi)聯(lián)函數(shù)過(guò)度創(chuàng)建新句柄

類成員函數(shù)不能保證 this

Hooks 優(yōu)勢(shì)

優(yōu)化類組件的三大問(wèn)題

函數(shù)組件無(wú) this 問(wèn)題

自定義 Hook 方便復(fù)用狀態(tài)邏輯

副作用的關(guān)注點(diǎn)分離

使用 State Hook
import React, {Component} from "react"

class App extends Component {
  state = {
    count: 0
  };
  render() {
    const {count} = this.state;
    return (
      
    )
  }
}
export default App;

以上代碼很好理解,點(diǎn)擊按鈕讓 count 值加 1

接下來(lái)我們使用 useState 來(lái)實(shí)現(xiàn)上述功能。

import React, {useState} from "react"

function App () {
  const [count, setCount] = useState(0)
  return (
    
  )
}

在這里,useState 就是一個(gè) Hook。通過(guò)在函數(shù)組件里調(diào)用它來(lái)給組件添加一些內(nèi)部 state,React 會(huì)在重復(fù)渲染時(shí)保留這個(gè) state

useState 會(huì)返回一對(duì)值:當(dāng)前狀態(tài)和一個(gè)讓你更新它的函數(shù)。你可以在事件處理函數(shù)中或其他一些地方調(diào)用這個(gè)函數(shù)。它類似 class 組件的 this.setState,但是它不會(huì)把新的 state 和舊的 state 進(jìn)行合并。useState 唯一的參數(shù)就是初始 state

useState 讓代碼看起來(lái)簡(jiǎn)潔了,但是我們可能會(huì)對(duì)組件中,直接調(diào)用 useState 返回的狀態(tài)會(huì)有些懵。既然 userState 沒(méi)有傳入任何的環(huán)境參數(shù),它怎么知道要返回的的是 count 的呢,而且還是這個(gè)組件的 count 不是其它組件的 count

初淺的理解: useState 確實(shí)不知道我們要返回的 count,但其實(shí)也不需要知道,它只要返回一個(gè)變量就行了。數(shù)組解構(gòu)的語(yǔ)法讓我們?cè)谡{(diào)用 useState 時(shí)可以給 state 變量取不同的名字。

useState 怎么知道要返回當(dāng)前組件的 state?

因?yàn)?JavaScript 是單線程的。在 useState 被調(diào)用時(shí),它只能在唯一一個(gè)組件的上下文中。

有人可能會(huì)問(wèn),如果組件內(nèi)有多個(gè) usreState,那 useState 怎么知道哪一次調(diào)用返回哪一個(gè) state 呢?

這個(gè)就是按照第一次運(yùn)行的次序來(lái)順序來(lái)返回的。

接著上面的例子我們?cè)诼暶饕粋€(gè) useState:

...
const [count, setScount] = useState(0)
const [name, setName] = useState("小智")
...

然后我們就可以斷定,以后APP組件每次渲染的時(shí)候,useState 第一次調(diào)用一定是返回 count,第二次調(diào)用一定是返回 name。不信的話來(lái)做個(gè)實(shí)驗(yàn):

let id = 0

function App () {
  let name,setName;
  let count,setCount;
  
  id += 1;
  if (id & 1) {
    // 奇數(shù)
    [count, setCount] = useState(0)
    [name, setName] = useState("小智")
  } else {
    // 偶數(shù)
    [name, setName] = useState("小智")
    [count, setCount] = useState(0)
  }

  return (
    
  )
}

首先在外部聲明一個(gè) id,當(dāng) id為奇數(shù)和偶數(shù)的時(shí)候分別讓 useState 調(diào)用方式相反,運(yùn)行會(huì)看到有趣的現(xiàn)象。

當(dāng)前版本如果寫(xiě)的順序不一致就會(huì)報(bào)錯(cuò)。

會(huì)發(fā)現(xiàn) countname 的取值串了。我們希望給 count 加 1,現(xiàn)在卻給 name 加了 1,說(shuō)明 setCount 函數(shù)也串成了 setName 函數(shù)。

為了防止我們使用 useState 不當(dāng),React 提供了一個(gè) ESlint 插件幫助我們檢查。

eslint-plugin-react-hooks

優(yōu)化點(diǎn)

通過(guò)上述我們知道 useState 有個(gè)默認(rèn)值,因?yàn)槭悄J(rèn)值,所以在不同的渲染周期去傳入不同的值是沒(méi)有意義的,只有第一次傳入的才有效。如下所示:

...
const defaultCount = props.defaultCount || 0
const [count, setCount] = useState(defaultCount)
...

state 的默認(rèn)值是基于 props,在 APP 組件每次渲染的時(shí)候 const defaultCount = props.defaultCount || 0 都會(huì)運(yùn)行一次,如果它復(fù)雜度比較高的話,那么浪費(fèi)的資料肯定是可觀的。

useState 支持傳入函數(shù),來(lái)延遲初始化:

const [count, setCount] = useState(() => {
  return props.defaultCount || 0
})

使用 Effect Hook

Effect Hook 可以讓你在函數(shù)組件中執(zhí)行副作用操作。數(shù)據(jù)獲取,設(shè)置訂閱以及手動(dòng)更改 React 組件中的 DOM 都屬于副作用。不管你知不知道這些操作,或是"副作用"這個(gè)名字,應(yīng)該都在組件中使用過(guò)它們。

副作用的時(shí)機(jī)

Mount 之后 對(duì)應(yīng) componentDidMount

Update 之后 對(duì)應(yīng) componentDidUpdate

Unmount 之前 對(duì)應(yīng) componentWillUnmount

現(xiàn)在使用 useEffect 就可以覆蓋上述的情況。

為什么一個(gè) useEffect 就能涵蓋 Mount,Update,Unmount 等場(chǎng)景呢。

useEffect 標(biāo)準(zhǔn)上是在組件每次渲染之后調(diào)用,并且會(huì)根據(jù)自定義狀態(tài)來(lái)決定是否調(diào)用還是不調(diào)用。

第一次調(diào)用就相當(dāng)于componentDidMount,后面的調(diào)用相當(dāng)于 componentDidUpdate。useEffect 還可以返回另一個(gè)回調(diào)函數(shù),這個(gè)函數(shù)的執(zhí)行時(shí)機(jī)很重要。作用是清除上一次副作用遺留下來(lái)的狀態(tài)。

比如一個(gè)組件在第三次,第五次,第七次渲染后執(zhí)行了 useEffect 邏輯,那么回調(diào)函數(shù)就會(huì)在第四次,第六次和第八次渲染之前執(zhí)行。嚴(yán)格來(lái)講,是在前一次的渲染視圖清除之前。如果 useEffect 是在第一次調(diào)用的,那么它返回的回調(diào)函數(shù)就只會(huì)在組件卸載之前調(diào)用了,也就是
componentWillUnmount 。

如果你熟悉 React class 的生命周期函數(shù),你可以把 useEffect Hook 看做componentDidMountcomponentDidUpdatecomponentWillUnmount 這三個(gè)函數(shù)的組合。

舉粟說(shuō)明一下:

class App extends Component {
  state = {
    count: 0,
    size: {
      width: document.documentElement.clientWidth,
      height: document.documentElement.clientHeight
    }
  };
  onResize = () => {
    this.setState({
      size: {
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight
      }
    })
  }
  componentDidMount () {
    document.title = this.state.count;
    window.addEventListener("resize", this.onResize, false)
  }
  componentWillMount () {
    window.removeEventListener("resize", this.onResize, false)
  }
  componentDidUpdate () {
    document.title = this.state.count;
  }
  render() {
    const {count, size} = this.state;
    return (
      
    )
  }
}

上面主要做的就是網(wǎng)頁(yè) title 顯示count 值,并監(jiān)聽(tīng)網(wǎng)頁(yè)大小的變化。這里用到了componentDidMount,componentDidUpdate 等副作用,因?yàn)榈谝淮螔燧d我們需要把初始值給 title, 當(dāng) count 變化時(shí),把變化后的值給它 title,這樣 title 才能實(shí)時(shí)的更新。

注意,我們需要在兩個(gè)生命周期函數(shù)中編寫(xiě)重復(fù)的代碼。

這邊我們?nèi)菀壮鲥e(cuò)的地方就是在組件結(jié)束之后要記住銷毀事件的注冊(cè),不然會(huì)導(dǎo)致資源的泄漏?,F(xiàn)在我們把 App 組件的副作用用 useEffect 實(shí)現(xiàn)。

function App (props) {
  const [count, setCount] = useState(0);

  const [size, setSize] = useState({
    width: document.documentElement.clientWidth,
    height: document.documentElement.clientHeight
  });

  const onResize = () => {
    setSize({
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight
      }
    )
  }

  useEffect(() => {
    document.title = count;
  })

  useEffect(() => {
    window.addEventListener("resize", onResize, false);
    return () => {
      window.removeEventListener("resize", onResize, false)
    }
  }, [])

  return (
    
  )
}

對(duì)于上述代碼的第一個(gè) useEffect,相比類組件,Hooks 不在關(guān)心是 mount 還是 update。用useEffect統(tǒng)一在渲染后調(diào)用,就完整追蹤了 count 的值。

對(duì)于第二個(gè) useEffect,我們可以通過(guò)返回一個(gè)回調(diào)函數(shù)來(lái)注銷事件的注冊(cè)?;卣{(diào)函數(shù)在視圖被銷毀之前觸發(fā),銷毀的原因有兩種:重新渲染和組件卸載

這邊有個(gè)問(wèn)題,既然 useEffect 每次渲染后都執(zhí)行,那我們每次都要綁定和解綁事件嗎?當(dāng)然是完全不需要,只要使用 useEffect 第二個(gè)參數(shù),并傳入一個(gè)空數(shù)組即可。第二個(gè)參數(shù)是一個(gè)可選的數(shù)組參數(shù),只有數(shù)組的每一項(xiàng)都不變的情況下,useEffect 才不會(huì)執(zhí)行。第一次渲染之后,useEffect 肯定會(huì)執(zhí)行。由于我們傳入的空數(shù)組,空數(shù)組與空數(shù)組是相同的,因此 useEffect 只會(huì)在第一次執(zhí)行一次。

這也說(shuō)明我們把 resize 相關(guān)的邏輯放在一直寫(xiě),不在像類組件那樣分散在兩個(gè)不同的生命周期內(nèi)。同時(shí)我們處理 title 的邏輯與 resize 的邏輯分別在兩個(gè) useEffect 內(nèi)處理,實(shí)現(xiàn)關(guān)注點(diǎn)分離。

我們?cè)诙x一個(gè) useEffect,來(lái)看看通過(guò)不同參數(shù),第二個(gè)參數(shù)的不同作用。

...
useEffect(() => {
  console.log("count:", count)
}, [count])
...

第二個(gè)參數(shù)我們傳入 [count], 表示只有 count 的變化時(shí),我才打印 count 值,resize 變化不會(huì)打印。

運(yùn)行效果如下:

第二個(gè)參數(shù)的三種形態(tài),undefined,空數(shù)組及非空數(shù)組,我們都經(jīng)歷過(guò)了,但是咱們沒(méi)有看到過(guò)回調(diào)函數(shù)的執(zhí)行。

現(xiàn)在有一種場(chǎng)景就是在組件中訪問(wèn) Dom 元素,在 Dom元素上綁定事件,在上述的代碼中添加以下代碼:

 ...
 const onClick = () => {
  console.log("click");
 }

 useEffect(() => {
   document.querySelector("#size").addEventListener("click", onClick, false);
 },[])
 
  return (
    
... size: {size.width}x{size.height}
)

新增一個(gè) DOM 元素,在新的 useEffect 中監(jiān)聽(tīng) span 元素的點(diǎn)擊事件。

運(yùn)行效果:

假如我們 span 元素可以被銷毀重建,我們看看會(huì)發(fā)生什么情況,改造一下代碼:

return (
  
... { count%2 ? 我是span :

我是p

}

運(yùn)行效果:

可以看出一旦 dom 元素被替換,我們綁定的事件就失效了,所以咱們始終要追蹤這個(gè)dom 元素的最新?tīng)顟B(tài)。

使用 useEffect ,最合適的方式就是使用回調(diào)函數(shù)來(lái)處理了,同時(shí)要保證每次渲染后都要重新運(yùn)行,所以不能給第二次參數(shù)設(shè)置 [],改造如下:

useEffect(() => {
 document.querySelector("#size").addEventListener("click", onClick, false);
   return () => {
     document.querySelector("#size").removeEventListener("click", onClick, false);
   }
})

運(yùn)行結(jié)果:

參考

React 官方文檔

《React勁爆新特性Hooks 重構(gòu)去哪兒網(wǎng)》

交流

React 官方文檔

《React勁爆新特性Hooks 重構(gòu)去哪兒網(wǎng)》

干貨系列文章匯總?cè)缦拢X(jué)得不錯(cuò)點(diǎn)個(gè)Star,歡迎 加群 互相學(xué)習(xí)。

https://github.com/qq44924588...

我是小智,公眾號(hào)「大遷世界」作者,對(duì)前端技術(shù)保持學(xué)習(xí)愛(ài)好者。我會(huì)經(jīng)常分享自己所學(xué)所看的干貨,在進(jìn)階的路上,共勉!

關(guān)注公眾號(hào),后臺(tái)回復(fù)福利,即可看到福利,你懂的。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/104868.html

相關(guān)文章

  • React 特性 Hooks 講解實(shí)例(四)

    摘要:粟例說(shuō)明一下獲取子組件或者節(jié)點(diǎn)的句柄指向已掛載到上的文本輸入元素本質(zhì)上,就像是可以在其屬性中保存一個(gè)可變值的盒子。粟例說(shuō)明一下渲染周期之間的共享數(shù)據(jù)的存儲(chǔ)上述使用聲明兩個(gè)副作用,第一個(gè)每隔一秒對(duì)加,因?yàn)橹恍鑸?zhí)行一次,所以每二個(gè)參為空數(shù)組。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你! React 新特性講解及實(shí)例(一) React 新特性 Hooks 講解及實(shí)...

    aboutU 評(píng)論0 收藏0
  • React 特性 Hooks 講解實(shí)例(三)

    摘要:來(lái)個(gè)使用類形式的例子以上就不說(shuō)解釋了,第一篇已經(jīng)講過(guò)了,接著將改成用的形式接著使用形式接收一個(gè)對(duì)象的返回值并返回該的當(dāng)前值。如果的返回值是函數(shù)的話,那么就可以簡(jiǎn)寫(xiě)成的方式,只是簡(jiǎn)寫(xiě)而已,實(shí)際并沒(méi)有區(qū)別。 本文是 React 系列的第三篇 React 新特性講解及實(shí)例(一) React 新特性 Hooks 講解及實(shí)例(二) 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著...

    _Dreams 評(píng)論0 收藏0
  • React 特性講解實(shí)例(一)

    摘要:接收一個(gè)屬性,這個(gè)組件會(huì)讓后代組件統(tǒng)一提供這個(gè)變量值。因此對(duì)于同一個(gè)對(duì)象而言,一定是后代元素。解決方法就是把內(nèi)聯(lián)函數(shù)提取出來(lái),如下講了這么多,我們還沒(méi)有講到其實(shí)我們已經(jīng)講完了的工作原理了。 本節(jié)主要講解以下幾個(gè)新的特性: Context ContextType lazy Suspense 錯(cuò)誤邊界(Error boundaries) memo 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博...

    Betta 評(píng)論0 收藏0
  • React系列 --- 從Mixin到HOC再到HOOKS(四)

    摘要:返回元素的是將新的與原始元素的淺層合并后的結(jié)果。生命周期方法要如何對(duì)應(yīng)到函數(shù)組件不需要構(gòu)造函數(shù)。除此之外,可以認(rèn)為的設(shè)計(jì)在某些方面更加高效避免了需要的額外開(kāi)支,像是創(chuàng)建類實(shí)例和在構(gòu)造函數(shù)中綁定事件處理器的成本。 React系列 React系列 --- 簡(jiǎn)單模擬語(yǔ)法(一)React系列 --- Jsx, 合成事件與Refs(二)React系列 --- virtualdom diff算法實(shí)...

    Lionad-Morotar 評(píng)論0 收藏0
  • React Hooks 解析(下):進(jìn)階

    摘要:第一次了解這項(xiàng)特性的時(shí)候,真的有一種豁然開(kāi)朗,發(fā)現(xiàn)新大陸的感覺(jué)。在絕大多數(shù)情況下,是更好的選擇。唯一例外的就是需要根據(jù)新的來(lái)進(jìn)行操作的場(chǎng)景。會(huì)保證在頁(yè)面渲染前執(zhí)行,也就是說(shuō)頁(yè)面渲染出來(lái)的是最終的效果。上面條規(guī)則都是為了保證調(diào)用順序的穩(wěn)定性。 歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、...

    APICloud 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<