定義:Hook 是一些可讓你在函數組件裏「鉤入」 React state 及生命週期等特性的函數。Hook 不能在 class 組件中使用 —— 這使得你不使用 class 也能使用 React。html
做用: React Hooks 要解決的是狀態共享問題,可是隻共享數據的處理邏輯,不會共享數據自己。react
- 組件間複用狀態邏輯複雜
- 難於理解的class
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
複製代碼
useEffect 默認狀況下在每次更新以後都會執行,使用useEffect能夠方便的訪問state或其餘props。 一個完整的effect的格式以下:json
useEffect(() => {
effect
return () => {
cleanup
};
}, [input])
複製代碼
其中是effect
是你須要執行的方法,return不是必須的,它返回的是一個清除機制。第二個參數[input]
也不是必須的,指的是effect
的依賴。若是第二個參數是[]
表示的是僅在掛載和卸載的時候執行,不傳表示在掛載和更新的時候執行。axios
解釋:每次 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>
);
}
複製代碼
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>
)
}
複製代碼
useRef
返回了一個ref對象,它是可變的,其
current
屬性指向的當前內容,而不是以前的快照。
如今有這樣一個需求,進入頁面後,須要一個數字不斷的加一,離開頁面後清除這個定時器,又因爲依賴了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
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
複製代碼
在上一節中,咱們發現更新和動做耦合在一塊兒,尤爲在一個useEffect依賴多個變量時候。useReducer
是useState
的替代方案,它接收(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>)
}
複製代碼
- 首先利用自定義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分頁請求表格數據:分頁請求