Hook
Hook 是 React 16.8.0
的新增特性癣防。
Hook 使你在非 class 的情況下可以使用更多的 React 特性。Hook 不能在 class 組件中使用芯咧。
使用規(guī)則:
- 只能在函數(shù)最外層調(diào)用 Hook。不要在循環(huán)、條件判斷或者子函數(shù)中調(diào)用唬党。
- 只能在 React 的函數(shù)組件中調(diào)用 Hook。不要在其他 JavaScript 函數(shù)中調(diào)用鬼佣。
State Hook
useState
使用useState可以不通過class組件而在函數(shù)組件內(nèi)使用state驶拱,可通過多次調(diào)用聲明多個state
-
參數(shù):
useState() 方法里面唯一的參數(shù)就是初始 state。
-
返回值:
當(dāng)前 state 以及更新 state 的函數(shù)晶衷。
函數(shù)式更新:
如果新的 state 需要通過使用先前的 state 計算得出蓝纲,那么可以將函數(shù)傳遞給 setState。該函數(shù)將接收先前的 state晌纫,并返回一個更新后的值税迷。
function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {count}
<button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
</>
);
}
Effect Hook
Effect Hook 可以讓你在函數(shù)組件中執(zhí)行副作用操作(在 React 組件中執(zhí)行過數(shù)據(jù)獲取、訂閱或者手動修改過 DOM锹漱。我們統(tǒng)一把這些操作稱為“副作用”箭养,或者簡稱為“作用”。)
useEffect
可以把 useEffect Hook 看做 componentDidMount哥牍,componentDidUpdate 和 componentWillUnmount 這三個函數(shù)的組合毕泌。
useEffect 會在每次渲染后(第一次渲染之后和每次更新之后)都執(zhí)行,如果你的 effect 返回一個函數(shù)嗅辣,React 將會在組件卸載的時候執(zhí)行清除操作時調(diào)用它撼泛。
useEffect在組件內(nèi)可多次調(diào)用,Hook 允許我們按照代碼的用途分離他們澡谭,React 將按照 effect 聲明的順序依次調(diào)用組件中的每一個 effect愿题。
使用位置:
組件內(nèi)部調(diào)用 useEffect。 將 useEffect 放在組件內(nèi)部讓我們可以在 effect 中直接訪問 count state 變量(或其他 props)蛙奖。
性能優(yōu)化:
useEffect 的第二個可選參數(shù)可以實現(xiàn)如果某些特定值在兩次重渲染之間沒有發(fā)生變化潘酗,你可以通知 React 跳過對 effect 的調(diào)用。請確保數(shù)組中包含了所有外部作用域中會隨時間變化并且在 effect 中使用的變量
// 僅在 count 更改時更新
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
示例代碼詳解 useState
與 useEffect
:
// 引入 React 中的 useState Hook外永。它讓我們在函數(shù)組件中存儲內(nèi)部 state
// 引入 useEffect
import React, { useState, useEffect } from 'react';
function Example(props) {
// 聲明了一個叫 count 的 state 變量崎脉,然后把它設(shè)為 0
const [count, setCount] = useState(0);
// 聲明第2個state
const [isOnline, setIsOnline] = useState(null);
// 無需清除的 effect
useEffect(() => {
// 將 document 的 title 設(shè)置為包含了點擊次數(shù)的消息。
document.title = `You clicked ${count} times`;
});
// 需要清除的 effect
useEffect(() => {
function handleFn(val) {
setIsOnline(val);
}
// 注冊監(jiān)聽
XXAPI.subscribe(handleFn);
// 清除監(jiān)聽
return () => {
XXAPI.unsubscribe(handleFn);
};
});
return (
<div>
// 讀取 State: 我們可以直接用 count
<p>You clicked {count} times</p>
// 更新 State: 可以通過調(diào)用 setCount 來更新當(dāng)前的 count
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useLayoutEffect
其函數(shù)簽名與 useEffect 相同伯顶,但它會在所有的 DOM 變更之后同步調(diào)用 effect囚灼。可以使用它來讀取 DOM 布局并同步觸發(fā)重渲染祭衩。在瀏覽器執(zhí)行繪制之前灶体,useLayoutEffect 內(nèi)部的更新計劃將被同步刷新。盡可能使用標(biāo)準(zhǔn)的 useEffect 以避免阻塞視覺更新掐暮。
與 componentDidMount 或 componentDidUpdate 不同蝎抽,使用 useEffect 調(diào)度的 effect 不會阻塞瀏覽器更新屏幕,這讓你的應(yīng)用看起來響應(yīng)更快。大多數(shù)情況下樟结,effect 不需要同步地執(zhí)行养交。在個別情況下(例如測量布局),這時需要用到useLayoutEffect
useRef
useRef 返回一個可變的 ref 對象瓢宦,其 .current 屬性被初始化為傳入的參數(shù)(initialValue)碎连。返回的 ref 對象在組件的整個生命周期內(nèi)保持不變。
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已掛載到 DOM 上的文本輸入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
useRef() 比 ref 屬性更有用驮履。它可以很方便地保存任何可變值鱼辙,其類似于在 class 中使用實例字段的方式。當(dāng) ref 對象內(nèi)容發(fā)生變化時玫镐,useRef 并不會通知你倒戏。變更 .current 屬性不會引發(fā)組件重新渲染。
自定義Hook
自定義Hook 是一個函數(shù)恐似,其名稱以 use
開頭(必須以 use
開頭)杜跷,函數(shù)內(nèi)部可以調(diào)用其他的 Hook。自定義Hook用于提取多組件之間的共享邏輯蹂喻,可用于替代 render props
和 HOC
葱椭。
在需要共享邏輯的組件內(nèi)調(diào)用很簡單,只需要引入定義好的自定義Hook口四,并傳入自己想要的參數(shù)拿到你想要的返回值作用于當(dāng)前組件孵运。
如下例:
- 提取自定義Hook:
import React, { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
- 使用自定義Hook:
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id);
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}