本文默認讀者對 React Hooks 已經有必定的瞭解。 所以再也不贅述 Hooks API 的使用了, 還未了解的同窗能夠去官網閱讀React Hooks API Referencejavascript
使用 React Hooks 就不得不提到 React 函數組件。html
Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called 「props」) and return React elements describing what should appear on the screen.java
從官網上的介紹來看, 組件就像 JavaScript 的函數, 它接收一些入參(props), 並返回 React 元素。react
在咱們最初學習使用 React 框架時, 首先了解的是經過Class
書寫組件, 這樣能夠很好地理解並規劃類組件
的數據與方法, 並且生命週期
可讓咱們更清晰地瞭解組件的加載以及更新狀態的觸發時機。git
那函數組件
呢? 函數組件
自己解決了從數據到 React 元素的映射, 而Hooks
則在此基礎上提供了數據存儲以及 Side Effect(反作用)的處理。github
此時此刻, 讓咱們忘記已經熟知的Class
與生命週期
, 來從新認識函數組件
+ Hooks
的 React。typescript
函數組件
是用來處理一些簡單的 UI 組件, 經過 Props 傳入的數據, 抽象封裝一些組件。數組
function Header(props) {
const { title, description, avatar } = props;
return (
<div> <img src={avatar} /> <h1>{title}</h1> <p>{description}</p> </div> ); } 複製代碼
限制了函數組件使用的緣由一方面在於它沒有內部數據, 另外一方面就是沒有生命週期, 所以沒法實現具備必定交互與邏輯的功能。閉包
函數組件內定義的變量不是固化的, 執行完成後, 函數內的變量就會被清理掉了(非閉包狀況)。因此, 咱們須要經過 Hooks 固化組件須要的一些數據。app
上面是 React Hooks 之 useState 的使用例子, 以下是淺嘗輒止的理解:
經過
useState
, 咱們在某個地方定義了一個對象, 並掛載到某個不會讓它消失的地方。useState
方法返回的第一個值就是咱們要的數據。useState
方法返回的第二個值是一個函數, 能夠設置這個對象的值, 而後會觸發函數從新渲染。
上面這坨話說的很模糊, 某個地方
究竟是哪一個地方, 定義了一個什麼樣的對象
, 又掛載到了什麼地方。設置了新值後又是怎麼觸發渲染的???
在瞭解Hook
加載前仍是要了解一下 Hook 的定義和存儲的。
下面是Hook
的 type 定義
export type Hook = {
// 數據
memoizedState: any,
// 下面這些暫時不須要了解
baseState: any,
baseQueue: Update<any, any> | null,
queue: UpdateQueue<any, any> | null,
// 鏈表下一個節點的指針
next: Hook | null,
};
複製代碼
咱們須要瞭解的是Hook
是經過鏈表
存儲的
第一個 Hook 會掛載到React Fiber Node
上, 以後在函數執行遇到的 Hook 會依次按順序掛載到 Hook 節點後。
函數執行遇到的 Hooks 會按照順序讀取React Fiber Node
上的 Hook 節點。
如上圖所示, 函數組件從新執行時是依賴 Hooks 隊列的順序的。若是在條件判斷
中使用 Hook 就會讓這個隊列錯亂。
所以也就會有以下官網提示:
Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.
反作用(Side Effect), 我的理解, 是在數據->視圖
的轉化過程當中, 出現的一些特別的時機
。咱們能夠利用這些時機
去處理一些業務邏輯。
如下是使用useEffect
的一個簡單的計數 Demo.
使用useEffect
去實如今渲染完成以後要去處理的一些事情。 你們也能夠在官網的 API Reference 中找到 React useEffect 說明。
咱們能夠經過流程圖加深理解useEffect
這個 Hook。
以上是useEffect
Hook 的大體執行邏輯, 經過此圖會發現useEffect
多了一步數據比對
的過程, 只有當如下條件成立時, SideEffect 纔會觸發調用。
咱們修改上面計數的例子就能夠更好的理解兩個 Hook。
function Demo(props) {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
useEffect(() => {
const timer = setTimeout(() => {
setCount(step + count);
}, 1000)
return () => {
clearTimeout(timer);
}
}, [count]);
return (
<div> <div>Count: {count}</div> <div>Step: {step}</div> <button onClick={() => { setCount(count + 1); }} > Click </button> </div>);
}
複製代碼
在 Gif 圖中, 在更新 Step 步長時, 計數第一次仍然是+1
, 隨後纔會+2
。
step
更新時, useEffect
的count
沒有變化, 因此沒有觸發更新useEffect
觸發時, 使用的是 Hook 中暫存的數據, 因此步長step
仍然是 1.咱們在 Hook 加載流程上補充上對比的過程。
Hook
中存入的是上一次渲染後的快照值, 因此在執行時, 也會使用上一次渲染留下來的值。
到這裏, 咱們歸納下函數組件的渲染流程
本文只是提到了useState
, useEffect
這兩例典型的 React Hooks。
以useState
爲例, 咱們瞭解了React Hooks
是如何解決函數組件內沒法保留內部數據的問題。
以useEffect
爲例, 咱們呢瞭解了React Hooks
如何處理在數據->視圖
之間一些時機
的處理
以及很淺顯的提到了Hook
中的數據暫存(快照)的緣由
React Hooks 還有不少種用法, 本章只是梳理 React Hooks 的一些基本概念。
PS: 下一章會着重於《如何在業務中梳理重組封裝本身的 Hooks》