讓你我不得不學習的React Hook

1 什麼是Hook

首先咱們要明白的是React 16.8 的新增特性。它可讓咱們在不編寫 class 的狀況下使用 state 以及其餘的 React 特性。那麼就會有一個問題,當咱們處理業務需求的時候,還須要用class嗎?在這裏告訴你們,仍是須要的,由於Hook目前還不能徹底知足咱們的業務需求,這點,下文會講到,那麼讓咱們來看一下勁爆的React Hook吧!(React 16.8.0 是第一個支持 Hook 的版本。升級時,請注意更新全部的 package,包括 React DOM。React Native 將在下一個穩定版本中支持 Hook。)react

第一個Hook:ajax

import React, { useState } from 'react';

function Example() {
  // 聲明一個新的叫作 「count」 的 state 變量
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

在這裏,說一下,useState 即是一個Hook,你是否是很好奇,一個計時器不一樣於咱們以往的寫法。編程

在這裏,useState 就是一個 Hook 。經過在函數組件裏調用它來給組件添加一些內部 state。React 會在重複渲染時保留這個 state。useState 會返回一對值:當前狀態和一個讓你更新它的函數,你能夠在事件處理函數中或其餘一些地方調用這個函數。它相似 class 組件的 this.setState,可是它不會把新的 state 和舊的 state 進行合併。數組

useState 惟一的參數就是初始 state。在上面的例子中,咱們的計數器是從零開始的,因此初始 state 就是 0。值得注意的是,不一樣於 this.state,這裏的 state 不必定要是一個對象 —— 若是你有須要,它也能夠是。這個初始 state 參數只有在第一次渲染的會被用到。瀏覽器

這裏推薦你們一個視頻

React 的今天和明天中英文雙字幕閉包

clipboard.png

那些年咱們開發中的痛點

  • 在組件之間複用狀態邏輯很難
  • 複雜組件變得難以理解
  • 難以理解的 class

那麼Hook能在哪些方面幫助咱們呢

  • 你可使用 Hook 從組件中提取狀態邏輯,使得這些邏輯能夠單獨測試並複用。Hook 使你在無需修改組件結構的狀況下複用狀態邏輯。 這使得在組件間或社區內共享 Hook 變得更便捷。
  • Hook 將組件中相互關聯的部分拆分紅更小的函數(好比設置訂閱或請求數據),而並不是強制按照生命週期劃分。你還可使用 reducer 來管理組件的內部狀態,使其更加可預測。
  • Hook 使你在非 class 的狀況下可使用更多的 React 特性。 從概念上講,React 組件一直更像是函數。而 Hook 則擁抱了函數,同時也沒有犧牲 React 的精神原則。Hook 提供了問題的解決方案,無需學習複雜的函數式或響應式編程技術

2 走進Hook

在上一章節咱們提到過一個簡單的計數器,那麼究竟什麼是Hook呢?Hook 是一些可讓你在函數組件裏「鉤入」 React state 及生命週期等特性的函數。那麼說白了,Hook並非什麼神奇的」人物「,只是一個咱們天天都在接觸實用的函數。dom

咱們仍然能夠聲明多個state變量

function ExampleWithManyStates() {
  // 聲明多個 state 變量!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}

如上所提到的useState 即是咱們在處理數據時的操做,那麼有沒有什麼好的辦法可讓我對行爲進行方便的處理呢。顯然是有的。當咱們作一些行爲的時候必然會有一些反作用的產生,這裏的反作用並非咱們生活中所提到的給一件事情帶來很差的影響,或者很差的效果。那麼究竟什麼是反作用呢?ide

關於反作用的理解

  • 理解反作用,咱們首先理解一下什麼是純函數:給一個 function 相同的參數,永遠會返回相同的值,而且沒有反作用;這個概念拿到 React 中,就是給一個 Pure component 相同的 props, 永遠渲染出相同的視圖,而且沒有其餘的反作用;純組件的好處是,容易監測數據變化、容易測試、提升渲染性能等;
  • 反作用(Side Effect)是指一個 function 作了和自己運算返回值無關的事,好比:修改了全局變量、修改了傳入的參數、甚至是 console.log(),因此 ajax 操做,修改 dom 都是算做反作用的

那麼,當咱們理解了反作用後,那麼咱們的useEffect 就是一個 Effect Hook,給函數組件增長了操做反作用的能力。它跟 class 組件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具備相同的用途,只不過被合併成了一個 API。函數

import React, { useState, useEffect } from 'react';

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

  // 至關於 componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    // 使用瀏覽器的 API 更新頁面標題
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

當你調用 useEffect 時,就是在告訴 React 在完成對 DOM 的更改後運行你的「反作用」函數。因爲反作用函數是在組件內聲明的,因此它們能夠訪問到組件的 props 和 state。默認狀況下,React 會在每次渲染後調用反作用函數 —— 包括第一次渲染的時候。性能

不得不注意的是

咱們能在全部的地"肆無忌憚"的使用如此之方便的Hook嗎,答案是暫時不能夠的,由於

  • 只能在函數最外層調用 Hook。不要在循環、條件判斷或者子函數中調用。
  • 只能在 React 的函數組件中調用 Hook。不要在其餘 JavaScript 函數中調用。(自定義Hook也能夠)

如何自定義Hook

自定義 Hook 更像是一種約定而不是功能。若是函數的名字以 「use」 開頭並調用其餘 Hook,咱們就說這是一個自定義 Hook。 useSomething 的命名約定可讓咱們的 linter 插件在使用 Hook 的代碼中找到 bug。

你能夠建立涵蓋各類場景的自定義 Hook,如表單處理、動畫、訂閱聲明、計時器,甚至可能還有更多咱們沒想到的場景。咱們很期待看到 React 社區會出現什麼樣的自定義 Hook。

3 分析Hook

首先讓Demo

1:  import React, { useState } from 'react'; //引入 React 中的 useState Hook。它讓咱們在函數組件中存儲內部 state。
 2:
 3:  function Example() {
 4:    const [count, setCount] = useState(0); //在 Example 組件內部,咱們經過調用 useState Hook 聲明瞭一個新的 state 變量。它返回一對值給到咱們命名的變量上。咱們把變量命名爲 count,由於它存儲的是點擊次數。咱們經過傳 0 做爲 useState 惟一的參數來將其初始化爲 0。第二個返回的值自己就是一個函數。它讓咱們能夠更新 count 的值,因此咱們叫它 setCount
 5:
 6:    return (
 7:      <div>
 8:        <p>You clicked {count} times</p>
 9:        <button onClick={() => setCount(count + 1)}> //當用戶點擊按鈕後,咱們傳遞一個新的值給 setCount。React 會從新渲染 Example 組件,並把最新的 count 傳給它。
10:         Click me
11:        </button>
12:      </div>
13:    );
14:  }
  • useState():它返回一個有兩個值的數組。第一個值是當前的 state,第二個值是更新 state 的函數。
  • count, setCount:它意味着咱們同時建立了 count 和 setCount 兩個變量,count 的值爲 useState 返回的第一個值,setCount 是返回的第二個值。
import React, { useState, useEffect } from 'react';

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

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useEffect 作了什麼?

經過使用這個 Hook,你能夠告訴 React 組件須要在渲染後執行某些操做。React 會保存你傳遞的函數(咱們將它稱之爲 「effect」),而且在執行 DOM 更新以後調用它。在這個 effect 中,咱們設置了 document 的 title 屬性,不過咱們也能夠執行數據獲取或調用其餘命令式的 API。

爲何在組件內部調用 useEffect?

將 useEffect 放在組件內部讓咱們能夠在 effect 中直接訪問 count state 變量(或其餘 props)。咱們不須要特殊的 API 來讀取它 —— 它已經保存函數做用域中。Hook 使用了 JavaScript 的閉包機制,而不用在 JavaScript 已經提供瞭解決方案的狀況下,還引入特定的 React API。

useEffect 會在每次渲染後都執行嗎?

是的,默認狀況下,它在第一次渲染以後和每次更新以後都會執行。(咱們稍後會談到如何控制它。)你可能會更容易接受 effect 發生在「渲染以後」這種概念,不用再去考慮「掛載」仍是「更新」。React 保證了每次運行 effect 的時,DOM 都已經更新完畢。

4 Hook API

基礎 Hook

  • useState
  • useEffect
  • useContext

額外的 Hook

  • useReducer
  • useCallback
  • useMemo
  • useRef
  • useImperativeHandle
  • useLayoutEffect
  • useDebugValue
相關文章
相關標籤/搜索