react hook 初體驗

定義:Hook 是一些可讓你在函數組件裏「鉤入」 React state 及生命週期等特性的函數。Hook 不能在 class 組件中使用 —— 這使得你不使用 class 也能使用 React。html

做用: React Hooks 要解決的是狀態共享問題,可是隻共享數據的處理邏輯,不會共享數據自己。react

1、優點

  1. 組件間複用狀態邏輯複雜
  2. 難於理解的class

2、State Hook基礎

useState 就是一個hook,它能夠給組件添加內部state,它會返回一對值,當前狀態和跟新它的函數。這個函數相似於class組件的this.setState 。 下面這個例子是最簡單的計數器:ios

import React, { useState } from 'react'
function Example({
  const [count, setCount] = useState(0)
  return (
    <div>       <button onClick={add}>點擊+1</button>       <p>點擊次數:{count}</p>     </div>
  )
  function add ({
    setCount (count + 1)
  }
}
export default Example
複製代碼

Image.png

3、Effect Hook

useEffect 默認狀況下在每次更新以後都會執行,使用useEffect能夠方便的訪問state或其餘props。 一個完整的effect的格式以下:json

useEffect(() => {
        effect
        return () => {
            cleanup
        };
    }, [input])
複製代碼

其中是effect是你須要執行的方法,return不是必須的,它返回的是一個清除機制。第二個參數[input]也不是必須的,指的是effect的依賴。若是第二個參數是[]表示的是僅在掛載和卸載的時候執行,不傳表示在掛載和更新的時候執行。axios

4、Capture Value 特性

解釋:每次 Render 的內容都會造成一個快照並保留下來,所以當狀態變動而 Rerender 時,就造成了 N 個 Render 狀態,而每一個 Render 狀態都擁有本身固定不變的 Props 與 State。什麼是Cature Value 以下面一個例子: `數組

function Example({
  const [count, setCount] = useState(0)
  return (<div><button onClick={add}>點擊測試</button></div>)
  function add({
    setCount(5)
    setTimeout(() => {
      // 結果是0而不是5
      console.log(count)
    }, 1000)
  }
}
複製代碼

打印的結果是0,而不是5,開始很讓人費解。根據Capture Value特性,第一次掛載組件的時候,count就已經造成了一份快照,並保留下來了。setTimeout裏面操做的count就是最開始的快照。 另外一個例子說明了這個問題:bash

function Example({
    const [count, setCount] = useState(0);
    useEffect(() => {
        setTimeout(() => {
            console.log(`You clicked ${count} times`);
        }, 3000);
    });
    return (
        <div>             <p>You clicked {count} times</p>             <button onClick={() => setCount(count + 1)}>                 Click me         </button>         </div>
    );
}
複製代碼

Image [1].png
在快速點擊按鈕多下以後,上面結果說明每次更新都有一個快照保存了下來,每次打印出來的是對應的快照內容,而不是最後一次。接着你會想,我如何才能取到當前真正的值呢,而不是舊值。你須要使用 useRef

function Example({
    const [count, setCount] = useState(0);
    const latestCount = useRef(count);
    useEffect(() => {
      latestCount.current = count;
      setTimeout(() => {
        console.log(`You clicked ${latestCount.current} times`);
      }, 3000);
    });
    return(
    <div>Count: {count}         <button  onClick={()=>{setCount(count+1)}} >點擊我</button>     </div>
    )
}
複製代碼

Image [2].png
useRef返回了一個ref對象,它是可變的,其 current屬性指向的當前內容,而不是以前的快照。

5、如何設置一個定時器

如今有這樣一個需求,進入頁面後,須要一個數字不斷的加一,離開頁面後清除這個定時器,又因爲依賴了count,那麼很容易想到下面這種寫法:async

function Example({
    const [count, setCount] = useState(0)
    useEffect(() => {
        let inter = setInterval(() => {
            setCount(count + 1)
            console.log('count-->', count)
        }, 1000)
        return () => {
            console.log('stopInterval-->', count)
            clearInterval(inter)
        };
    }, [count])
    return (<div>         當前的值是:{count}     </div>)
}
複製代碼

發現定時器能正常進行,而且頁面能夠顯示數字: ide

Image [3].png
可是:爲何會不斷的新建定時器後又銷燬呢?這樣實在是太不高效了。
Image [4].png
原來是由於 useEffect依賴了 count,當 count改變後又反過來執行 useEffect,其實setCount 還有函數回調方式,不用關心當前值。

function Example({
    const [count, setCount] = useState(0)
    useEffect(() => {
        let inter = setInterval(() => {
            setCount(c => c + 1)
        }, 1000)
        return () => {
            clearInterval(inter)
              };
    }, [])
    return (<div>         當前的值是:{count}     </div>)
}
export default Example
複製代碼

6、useReducer

在上一節中,咱們發現更新和動做耦合在一塊兒,尤爲在一個useEffect依賴多個變量時候。useReduceruseState的替代方案,它接收(state, action) => newState方法,它返回一個數組,相似於useState hook,第一個是當前狀態,第二個是dispatch方法。函數

    const [state, dispatch] = useReducer(reducer, initialState, init)
複製代碼

利用useReducer能夠重寫最開始的加法器:

function Example({
    const [count, dispatch] = useReducer(reducer, 0)
    function reducer (state, action{
        return action.type === 'add' ? state + 1 :state - 1
    }
    return (<div>         <button onClick={() => {dispatch({type: 'add'})}}>+1</button>         <button onClick={() => {dispatch({type: 'decrement'})}}>-1</button>         當前的值是:{count}     </div>)
}
複製代碼

Image [5].png

7、其餘hooks

查看官方文檔 自定義Hook其餘Hook

8、使用自定義Hook封裝axios

  1. 首先利用自定義Hooks 實現一個fetchApi,傳入一個axios和參數params,返回結果data
function useFetch(fetch, params{
    const [data, setData] = useState({});
    const fetchApi = useCallback(async () => {
        const res = await fetch(params);
        if (res.code === 1) {
            setData(res.data);
        }
    }, [fetch, params]);
    useEffect(() => {
        fetchApi();
    }, [fetchApi]);
    return data;
}
複製代碼

提供一個axios方法fetch

export const fetch = params => {
    const url = 'baseUrl' + (params);
    return axios(url).then(res => res.json());
};
複製代碼

去使用這個useFetch

function Demo({
    const data = useFetch(fetch, { params1"xxx" }
    return <div>獲得返回值:{data}</div>;
}
複製代碼

結果發現,這樣並不行得通,一會兒程序就會陷入死循環,好好分析一下,原來params是一個對象,usecallback會誤認爲每次params都改變了,致使陷入了一個死循環中。:render -->useEffect-->useCllback--->data改變--->render,那麼天然而然就會想到useMemo,它使得數據項真正的改變時候纔會使得useCallback從新執行。或者使用JSON.stringify轉換params 便可。

params = useMemo(() => (params), []);
複製代碼

這裏有個較爲完整的例子,如何使用hooks分頁請求表格數據:分頁請求

相關文章
相關標籤/搜索