在 React 專案中,我們經常會使用到 React 自帶的幾個內建 Hooks,如 useState,useContext 和useEffect。但有時,我們可能希望有一個特定目的的 Hook :例如取得資料 useData,取得連接 useConnect 等。雖然在 React 中找不到這些 Hooks,但 React 提供了非常靈活的方式讓你為自己的需求來創建自己的自訂 Hooks。
如何自訂Hooks
在React 中你必須遵循以下命名約定:
React Component: React 元件名稱必須以大寫字母開頭,如StatusBar 和SaveButton。 React元件也需要 回傳 一些React知道如何渲染的東西,像是
JSX
。React Hook: Hook 名必須以use 開頭,後面跟著一個大寫字母,例如useState (內建)或useStatus (自訂)。與 React 元件不同的是自訂 Hook 可以傳回任意值。
這個命名約定確保你始終可以查看元件,並了解其狀態、效果以及其他React 特性可能「隱藏」的位置。例如,如果你在元件中看到 getColor() 函數調用,你可以確定它不可能包含 React state,因為其名稱不以use開頭。但是,像 useStatus() 這樣的函數呼叫很可能包含對其他 Hooks 的呼叫!
元件之間共享邏輯
The code inside them describes what they want to do rather than how to do it .
自訂Hooks 的核心是共享元件之間的邏輯。使用自訂 Hooks 能夠減少重複的邏輯,更重要的是,自訂 Hooks 內部的程式碼描述了它們想做什麼,而不是如何做。當你將邏輯提取到自訂Hooks 中時,你可以隱藏如何處理某些"外部系統"或瀏覽器API 的呼叫的細節,元件的程式碼表達的是你的意圖,而不是實作細節。 下面是一個簡單的範例:
import { useState } from 'react'; function useCounter(initialValue) { const [count, setCount] = useState(initialValue); function increment() { setCount(count + 1); } return [count, increment]; }
這個自訂Hook 叫做 useCounter
,它接受一個初始值作為參數,並且傳回一個數組,包含目前的計數值和一個增加計數的函數。
使用自訂 Hook 非常簡單,只需要在函數元件中呼叫它。以下是使用 useCounter
的範例:
import React from 'react'; import useCounter from './useCounter'; function Counter() { const [count, increment] = useCounter(0); return ( <div> <p>Count: {count}</p> <button onClick={increment}>Increment</button> </div> ); }
在這個範例中,我們匯入了 useCounter
,並在元件中呼叫它。我們將傳回的陣列解構為 count
和 increment
,然後在元件中使用它們。
自訂 Hooks 允許你共享有狀態邏輯,而不是狀態本身
自訂 Hooks 允許共享有狀態邏輯,但不能共享狀態本身。每個對 Hook 的呼叫都完全獨立於對同一個 Hook 的其他呼叫。
以上面的useCounter
為例:
import useCounter from './useCounter'; function Counter() { const [count1, increment1] = useCounter(0); const [count2, increment2] = useCounter(100); return ( <div> <p>Count1: {count1}</p> <button onClick={increment1}>Increment1</button> <p>Count2: {count2}</p> <button onClick={increment2}>Increment2</button> </div> ); }
當我們點擊Increment2
時,並不會影響count1
,因為每一個 useCounter
的呼叫都是獨立的,其內部狀態也是獨立的。
分類
功能型Hooks
以實現特定功能或目的,與具體業務無關:
useWindowWidth
該hook 返回視窗寬度的值。
import { useState, useEffect } from 'react'; function useWindowWidth() { const [windowWidth, setWindowWidth] = useState(window.innerWidth); useEffect(() => { const handleResize = () => setWindowWidth(window.innerWidth); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); return windowWidth; }
useLocalStorage
該 hook 允許你在本機儲存中儲存和檢索值。
import { useState } from 'react'; 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 { setStoredValue(value); window.localStorage.setItem(key, JSON.stringify(value)); } catch (error) { console.log(error); } }; return [storedValue, setValue]; }
業務型 Hooks
useFetch
該 hook 允許你從 API 取得資料。
import { useState, useEffect } from 'react'; function useFetch(url) { const [data, setData] = useState(null); const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(true); useEffect(() => { const fetchData = async () => { try { const response = await fetch(url); const json = await response.json(); setData(json); } catch (error) { setError(error); } finally { setIsLoading(false); } }; fetchData(); }, [url]); return { data, error, isLoading }; }
useModal
該 hook 允許你管理模態對話方塊的狀態。
//useFetch.js import {useState, useEffect} from 'react' //don't forget to give a url parameter for the function. const useFetch = (url)=>{ const [data, setData] = useState([]) const getData = async ()=>{ const response = await fetch(url) const userdata = await response.json() setData(userdata) } useEffect(()=>{ getData() },[url]) //return data that we will need in other components. return {data}; } export default useFetch;
在多個 Hook 之間傳遞訊息
由於 Hook 本身就是函數,因此我們可以在它們之間傳遞訊息。下面我們以useUserInfo
取得使用者資訊為例:
//useUserInfo.jsx import { useEffect,useState } from 'react' const useUserInfo = (userId) => { const [userInfo, setUserInfo] = useState({}) useEffect(() => { fetch('/user') .then(res => res.json()) .then(data => setUserInfo(data)) }, [userId]) return userInfo } //Home.jsx ... const Home = ()=>{ const [userId,setUserId] = useState('103') const useInfo = useUserInfo(userId) return ( <> <div>name:{userInfo.name}</div> <div>age:{userInfo.age}</div> ... </> ) }
我們將使用者id 保存在userId
狀態變數中,當使用者進行某一動作#setUserId
時,由於 useState
為我們提供了 userId
狀態變數的最新值,因此我們可以將它傳遞給自訂的 useUserInfo
Hook :
const [userId,setUserId] = useState('103') const userInfo = useUserInfo(userId)
此時,我們的userInfo
會隨著userId 的改變而更新。
將 event handlers 傳遞給自訂 Hooks
This section describes an experimental API that has not yet been released in a stable version of React. 本節描述了一個尚未在 React 穩定版本中發布的 實驗性 API。
你可能希望让组件自定义其行为,而不是完全地将逻辑封装 Hooks 中,我们可以通过将 event handlers
作为参数传递给 Hooks,下面是一个聊天室的例子:useChatRoom
接受一个服务端 url 和 roomId,当调用这个 Hook 的时候,会进行连接,
export function useChatRoom({ serverUrl, roomId }) { useEffect(() => { const options = { serverUrl: serverUrl, roomId: roomId }; const connection = createConnection(options); connection.connect(); connection.on('message', (msg) => { showNotification('New message: ' + msg); }); return () => connection.disconnect(); }, [roomId, serverUrl]); }
假设当连接成功时,你想将此逻辑移回你的组件:
export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl, onReceiveMessage(msg) { showNotification('New message: ' + msg); } }); // ...
要做到这一点,改变你的自定义 Hook ,把 onReceiveMessage
作为它的命名选项之一:
export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) { useEffect(() => { const options = { serverUrl: serverUrl, roomId: roomId }; const connection = createConnection(options); connection.connect(); connection.on('message', (msg) => { onReceiveMessage(msg); }); return () => connection.disconnect(); }, [roomId, serverUrl, onReceiveMessage]); // ✅ All dependencies declared }
这可以工作,但是当你的自定义 Hook 接受事件处理程序时,你还可以做一个改进。
在 onReceiveMessage
上添加依赖并不理想,因为它会导致每次组件重新渲染时聊天都重新连接。将此事件处理程序包装到 EffectEvent
中以将其从依赖项中移除:
import { useEffect, useEffectEvent } from 'react'; // ... export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) { const onMessage = useEffectEvent(onReceiveMessage); useEffect(() => { const options = { serverUrl: serverUrl, roomId: roomId }; const connection = createConnection(options); connection.connect(); connection.on('message', (msg) => { onMessage(msg); }); return () => connection.disconnect(); }, [roomId, serverUrl]); // ✅ All dependencies declared }
现在不会在每次重新渲染聊天室组件时进行重新连接。
开源 React Hooks 库
- ahooks 一套由阿里巴巴开源的 React Hooks 库,封装了大量好用的 Hooks。
- react-use 一个必不可少的 React Hooks 集合。其包含了传感器、用户界面、动画效果、副作用、生命周期、状态这六大类的Hooks。
- useHooks 一组易于理解的 React Hook集合。
- react-recipes 一个包含流行的自定义 Hook 的 React Hooks 实用程序库。
- Rhooks 一组基本的 React 自定义Hooks。
- react-hanger 一组有用的 hooks,用于特定于某些基本类型的状态更改辅助函数。
- Beautiful React Hook 一组漂亮的(希望有用的)React hooks 来加速你的组件和 hooks 开发。
- Awesome React Hooks 一个很棒的 React Hooks 资源集合,该集合包含React Hooks教程、视频、工具,Hooks列表。其中Hooks列表中包含了众多实用的自定义Hooks。
- SWR 一个用于获取数据的 React Hooks 库。只需一个Hook,就可以显着简化项目中的数据获取逻辑。
- React Hook Form 一个用于表单状态管理和验证的 React Hooks (Web + React Native)。
总结
自定义 Hooks 可以帮助你迁移到更好的开发范式。通过将一些通用逻辑封装在自定义 Hooks 中,你可以使组件代码保持简洁并专注于核心意图,这有助于减少重复性的代码,并使你的代码更易于维护和更新,从而使你能够更快速地开发新功能。
对于 Effect 而言,这样可以使数据在 Effects 中流动的过程变得非常明确。这让你的组件能够专注于意图,而不是 Effects 的具体实现。当 React 添加新功能时,你可以删除那些 Effects 而不影响任何组件。就像设计系统一样,你可能会发现从应用程序组件中提取常见习惯用法到自定义 Hooks 中是有非常帮助的。这将使你的组件代码专注于意图,并允许你避免频繁编写原始 Effects,这也是 React 开发者所推崇的。
(學習影片分享:程式設計基礎影片)
以上是深入理解React的自訂Hook的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

Atom編輯器mac版下載
最受歡迎的的開源編輯器

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。