国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

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

zero / 2778人閱讀

摘要:還可以返回另一個回調函數,這個函數的執行時機很重要。對于第二個我們可以通過返回一個回調函數來注銷事件的注冊。回調函數在視圖被銷毀之前觸發,銷毀的原因有兩種重新渲染和組件卸載。

本文是 React 系列的第二篇

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

想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你!

什么是 Hooks

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

類組件的不足

狀態邏輯復用難

缺少復用機制

渲染屬性和高階組件導致層級冗余

趨向復雜難以維護

生命周期函數混雜不相干邏輯

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

this 指向困擾

內聯函數過度創建新句柄

類成員函數不能保證 this

Hooks 優勢

優化類組件的三大問題

函數組件無 this 問題

自定義 Hook 方便復用狀態邏輯

副作用的關注點分離

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

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

以上代碼很好理解,點擊按鈕讓 count 值加 1

接下來我們使用 useState 來實現上述功能。

import React, {useState} from "react"

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

在這里,useState 就是一個 Hook。通過在函數組件里調用它來給組件添加一些內部 state,React 會在重復渲染時保留這個 state

useState 會返回一對值:當前狀態和一個讓你更新它的函數。你可以在事件處理函數中或其他一些地方調用這個函數。它類似 class 組件的 this.setState,但是它不會把新的 state 和舊的 state 進行合并。useState 唯一的參數就是初始 state

useState 讓代碼看起來簡潔了,但是我們可能會對組件中,直接調用 useState 返回的狀態會有些懵。既然 userState 沒有傳入任何的環境參數,它怎么知道要返回的的是 count 的呢,而且還是這個組件的 count 不是其它組件的 count

初淺的理解: useState 確實不知道我們要返回的 count,但其實也不需要知道,它只要返回一個變量就行了。數組解構的語法讓我們在調用 useState 時可以給 state 變量取不同的名字。

useState 怎么知道要返回當前組件的 state?

因為 JavaScript 是單線程的。在 useState 被調用時,它只能在唯一一個組件的上下文中。

有人可能會問,如果組件內有多個 usreState,那 useState 怎么知道哪一次調用返回哪一個 state 呢?

這個就是按照第一次運行的次序來順序來返回的。

接著上面的例子我們在聲明一個 useState:

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

然后我們就可以斷定,以后APP組件每次渲染的時候,useState 第一次調用一定是返回 count,第二次調用一定是返回 name。不信的話來做個實驗:

let id = 0

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

  return (
    
  )
}

首先在外部聲明一個 id,當 id為奇數和偶數的時候分別讓 useState 調用方式相反,運行會看到有趣的現象。

當前版本如果寫的順序不一致就會報錯。

會發現 countname 的取值串了。我們希望給 count 加 1,現在卻給 name 加了 1,說明 setCount 函數也串成了 setName 函數。

為了防止我們使用 useState 不當,React 提供了一個 ESlint 插件幫助我們檢查。

eslint-plugin-react-hooks

優化點

通過上述我們知道 useState 有個默認值,因為是默認值,所以在不同的渲染周期去傳入不同的值是沒有意義的,只有第一次傳入的才有效。如下所示:

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

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

useState 支持傳入函數,來延遲初始化:

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

使用 Effect Hook

Effect Hook 可以讓你在函數組件中執行副作用操作。數據獲取,設置訂閱以及手動更改 React 組件中的 DOM 都屬于副作用。不管你知不知道這些操作,或是"副作用"這個名字,應該都在組件中使用過它們。

副作用的時機

Mount 之后 對應 componentDidMount

Update 之后 對應 componentDidUpdate

Unmount 之前 對應 componentWillUnmount

現在使用 useEffect 就可以覆蓋上述的情況。

為什么一個 useEffect 就能涵蓋 Mount,Update,Unmount 等場景呢。

useEffect 標準上是在組件每次渲染之后調用,并且會根據自定義狀態來決定是否調用還是不調用。

第一次調用就相當于componentDidMount,后面的調用相當于 componentDidUpdateuseEffect 還可以返回另一個回調函數,這個函數的執行時機很重要。作用是清除上一次副作用遺留下來的狀態。

比如一個組件在第三次,第五次,第七次渲染后執行了 useEffect 邏輯,那么回調函數就會在第四次,第六次和第八次渲染之前執行。嚴格來講,是在前一次的渲染視圖清除之前。如果 useEffect 是在第一次調用的,那么它返回的回調函數就只會在組件卸載之前調用了,也就是
componentWillUnmount

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

舉粟說明一下:

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 (
      
    )
  }
}

上面主要做的就是網頁 title 顯示count 值,并監聽網頁大小的變化。這里用到了componentDidMountcomponentDidUpdate 等副作用,因為第一次掛載我們需要把初始值給 title, 當 count 變化時,把變化后的值給它 title,這樣 title 才能實時的更新。

注意,我們需要在兩個生命周期函數中編寫重復的代碼。

這邊我們容易出錯的地方就是在組件結束之后要記住銷毀事件的注冊,不然會導致資源的泄漏。現在我們把 App 組件的副作用用 useEffect 實現。

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 (
    
  )
}

對于上述代碼的第一個 useEffect,相比類組件,Hooks 不在關心是 mount 還是 update。用useEffect統一在渲染后調用,就完整追蹤了 count 的值。

對于第二個 useEffect,我們可以通過返回一個回調函數來注銷事件的注冊。回調函數在視圖被銷毀之前觸發,銷毀的原因有兩種:重新渲染和組件卸載

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

這也說明我們把 resize 相關的邏輯放在一直寫,不在像類組件那樣分散在兩個不同的生命周期內。同時我們處理 title 的邏輯與 resize 的邏輯分別在兩個 useEffect 內處理,實現關注點分離。

我們在定義一個 useEffect,來看看通過不同參數,第二個參數的不同作用。

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

第二個參數我們傳入 [count], 表示只有 count 的變化時,我才打印 count 值,resize 變化不會打印。

運行效果如下:

第二個參數的三種形態,undefined,空數組及非空數組,我們都經歷過了,但是咱們沒有看到過回調函數的執行。

現在有一種場景就是在組件中訪問 Dom 元素,在 Dom元素上綁定事件,在上述的代碼中添加以下代碼:

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

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

新增一個 DOM 元素,在新的 useEffect 中監聽 span 元素的點擊事件。

運行效果:

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

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

我是p

}

運行效果:

可以看出一旦 dom 元素被替換,我們綁定的事件就失效了,所以咱們始終要追蹤這個dom 元素的最新狀態。

使用 useEffect ,最合適的方式就是使用回調函數來處理了,同時要保證每次渲染后都要重新運行,所以不能給第二次參數設置 [],改造如下:

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

運行結果:

參考

React 官方文檔

《React勁爆新特性Hooks 重構去哪兒網》

交流

React 官方文檔

《React勁爆新特性Hooks 重構去哪兒網》

干貨系列文章匯總如下,覺得不錯點個Star,歡迎 加群 互相學習。

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

我是小智,公眾號「大遷世界」作者,對前端技術保持學習愛好者。我會經常分享自己所學所看的干貨,在進階的路上,共勉!

關注公眾號,后臺回復福利,即可看到福利,你懂的。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/104868.html

相關文章

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

    摘要:粟例說明一下獲取子組件或者節點的句柄指向已掛載到上的文本輸入元素本質上,就像是可以在其屬性中保存一個可變值的盒子。粟例說明一下渲染周期之間的共享數據的存儲上述使用聲明兩個副作用,第一個每隔一秒對加,因為只需執行一次,所以每二個參為空數組。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! React 新特性講解及實例(一) React 新特性 Hooks 講解及實...

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

    摘要:來個使用類形式的例子以上就不說解釋了,第一篇已經講過了,接著將改成用的形式接著使用形式接收一個對象的返回值并返回該的當前值。如果的返回值是函數的話,那么就可以簡寫成的方式,只是簡寫而已,實際并沒有區別。 本文是 React 系列的第三篇 React 新特性講解及實例(一) React 新特性 Hooks 講解及實例(二) 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著...

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

    摘要:接收一個屬性,這個組件會讓后代組件統一提供這個變量值。因此對于同一個對象而言,一定是后代元素。解決方法就是把內聯函數提取出來,如下講了這么多,我們還沒有講到其實我們已經講完了的工作原理了。 本節主要講解以下幾個新的特性: Context ContextType lazy Suspense 錯誤邊界(Error boundaries) memo 想閱讀更多優質文章請猛戳GitHub博...

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

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

    Lionad-Morotar 評論0 收藏0
  • React Hooks 解析(下):進階

    摘要:第一次了解這項特性的時候,真的有一種豁然開朗,發現新大陸的感覺。在絕大多數情況下,是更好的選擇。唯一例外的就是需要根據新的來進行操作的場景。會保證在頁面渲染前執行,也就是說頁面渲染出來的是最終的效果。上面條規則都是為了保證調用順序的穩定性。 歡迎關注我的公眾號睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、...

    APICloud 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<