React是一個可重複使用的UI組件庫,而自定義Hook讓我們可以使用自己的邏輯來將一些行為等移到可重複使用的函數中,方便代碼的復用和組合。
一、Hook的簡介
React Hook是在React16.8版本新增的一項特性。它允許您在不編寫 Class 組件的情況下使用狀態(state)和其它 React 特性。它們是一個允許您在函數組件中添加狀態和其他React功能的方法。
使用hooks,就可以在不編寫Class組件的情況下,使用狀態(state)等react特性, 無需改變組件的層級,更容易的實現復用和組合。
二、何為自定義Hook?
自定義hook使得你可以使用功能組件實現狀態邏輯復用。自定義hook是一個函數,命名以use為前綴,函數內部可以調取別的hook。自定義hook可以將組件的狀態邏輯提取到可重用的函數中。
function useCustomHook() {
//調用state或Effect等hook
const [count, setCount] = useState(0);
useEffect(() => {
//登場效果
});
//自定義函數
function handleCount() {
setCount(count + 1);
}
//返回數據
return {
count,
handleCount,
};
}
function CustomComponent() {
//調用自定義hook
const { count, handleCount } = useCustomHook();
//返回展示效果
return (
<div>
<p>The count is {count}</p>
<button onClick={handleCount}>Click me</button>
</div>
);
}
三、實現業務邏輯分離
使用自定義hook使得我們可以把共同的業務邏輯放在一起。例如,當我們需要處理本地存儲的請求時,無需在每一個需要本地存儲的組件重複去寫hook獲取存儲值。
下面是一個實現LocalStorage邏輯分離的例子:
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.log(error);
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.log(error);
}
};
return [storedValue, setValue];
}
function CustomComponent() {
const [name, setName] = useLocalStorage("name", "");
//返回展示效果
return (
<div>
<p>My name is {name}</p>
<button onClick={() => setName("John Doe")}>Set name to John Doe</button>
</div>
);
}
四、組件與非組件hook的區別
自定義hook既可以作為組件的hook使用,也可以是非組件的hook。不過對於組件hook與非組件hook在實現上有一定的區別:
- 組件hook可以依賴參數進行更新,除此之外的非組件hook是用來實現通用邏輯。
- 組件hook可以返回待渲染的JSX,而非組件hook則是返回狀態和操作函數。
//組件hook
function useScrollTop() {
const [scrollTop, setScrollTop] = useState(false);
useEffect(() => {
function handleScroll() {
setScrollTop(window.scrollY > 0);
}
document.addEventListener('scroll', handleScroll);
return () => {
document.removeEventListener('scroll', handleScroll);
}
}, []);
return <div style={{ position: 'fixed', top: '18px', right: '30px' }}>{scrollTop&&<a href="#top">UP</a>}</div>;
}
//非組件hook
function useNotification(title, options) {
if (!("Notification" in window)) {
return;
}
const [permission] = useState(Notification.permission);
const [notification, setNotification] = useState(null);
const handleNotification = () => {
const notification = new Notification(title, options);
setNotification(notification);
};
const checkNotificationPromise = () => {
try {
Notification.requestPermission().then();
} catch (e) {
return false;
}
return true;
};
const requestNotificationPermission = async () => {
if (permission === "granted") {
handleNotification();
} else if (permission !== "denied") {
const permission = await Notification.requestPermission();
if (permission === "granted") {
handleNotification();
}
}
};
useEffect(() => {
if (permission === "granted") {
requestNotificationPermission();
} else if (permission === "default") {
checkNotificationPromise();
}
return () => {
if (notification) {
notification.close();
}
};
}, []);
}
五、自定義Hook對流程式控制制的影響
自定義hook聚焦於某些行為,以讓組件對他們進行使用而不需要關心實現細節。自定義hook讓組件更容易組合、共享行為,而無需關心時間的實現細節。
而對於每一個使用Effect的組件,都需要在componentDidMount和componentDidUnMount中組合其中的一些行為。這些代碼很容易出錯、難以閱讀、難以恢復,並且難以測試。
自定義Hook讓我們可以將這種代碼和行為分離,同時讓我們的組件不那麼臃腫。自定義Hook可以針對一個特定的行為,而不是一個組件,從而更好地實現復用和組合。
六、結語
自定義hook使得我們可以將代碼結構更加清晰和易於復用。從我們的應用程序中抽象出類似於useEffect、useState、useRef和useReducer的概念,並使用它們構建更高層次的抽象,可以更好地表達我們的意圖,發現隱式複雜性。
在任何情況下,請記住重構代碼並不總是意味著把所有東西重新設計到新的地方。根據需要使用自定義hook或者組件可以使代碼更易於維護和擴展。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/242242.html