React中Hooks邏輯復用的實現(xiàn)
前言
在 React 開發(fā)中,Hooks 的出現(xiàn)徹底改變了邏輯復用的方式。它讓我們能夠將復雜的、可復用的邏輯從 UI 組件中抽離,實現(xiàn)真正的“關注點分離”。本文將分享 Hooks 的核心原則,并提供 4 個在真實業(yè)務場景中封裝的實戰(zhàn)案例。
一、 Hooks 核心
1. 概念理解
Hooks 本質上是將組件間共享的邏輯抽離并封裝成的特殊函數(shù)。
2. 使用“紅線”:規(guī)則與原理
- 命名規(guī)范:必須以
use開頭(如useChat),這不僅是約定,也是靜態(tài)檢查工具(ESLint)識別 Hook 的依據。 - 調用位置:嚴禁在循環(huán)、條件判斷或嵌套函數(shù)中調用 Hook。
底層原理: React 內部并不是通過“變量名”來記錄 Hook 狀態(tài)的,而是通過鏈表 。每次渲染時,React 嚴格依賴 Hook 的調用順序來查找對應的狀態(tài)。
注意: 如果在 if 語句中調用 Hook,一旦條件不成立導致某次渲染跳過了該 Hook,整個鏈表的指針就會錯位,導致狀態(tài)讀取異常。
二、 實戰(zhàn):自定義 Hooks 封裝
1. AI 場景:消息點贊/點踩邏輯 (useChatEvaluate)
在 AI 對話系統(tǒng)中,消息評價是通用功能。我們需要處理:狀態(tài)切換(點贊 -> 取消點贊)、單選邏輯、以及異步接口調用。
import React, { useState } from 'react';
// 模擬接口
const public_evaluateMessage = async (params: any) => ({ data: true });
type EvaluateType = "GOOD" | "BAD" | "NONE";
export const useChatEvaluate = (initialType: EvaluateType = "NONE") => {
const [ratingType, setRatingType] = useState<EvaluateType>(initialType);
const evaluateMessage = async (contentId: number, type: "GOOD" | "BAD") => {
let newEvaluateType: EvaluateType;
// 邏輯:如果點擊已選中的類型,則取消選中(NONE);否則切換到新類型
if (type === "GOOD") {
newEvaluateType = ratingType === "GOOD" ? "NONE" : "GOOD";
} else {
newEvaluateType = ratingType === "BAD" ? "NONE" : "BAD";
}
try {
const res = await public_evaluateMessage({
contentId,
ratingType: newEvaluateType,
content: "",
});
if (res.data === true) {
setRatingType(newEvaluateType);
}
} catch (error) {
console.error("評價失敗:", error);
}
};
return { ratingType, evaluateMessage };
};
// 使用示例
const ChatMessage: React.FC<{ id: number }> = ({ id }) => {
const { ratingType, evaluateMessage } = useChatEvaluate();
return (
<button onClick={() => evaluateMessage(id, "GOOD")}>
{ratingType === "GOOD" ? "?? 已點贊" : "?? 點贊"}
</button>
);
};
2. 響應式布局:屏幕尺寸監(jiān)聽 (useMediaSize)
在響應式系統(tǒng)中,封裝一個能根據窗口寬度自動切換“設備類型”的 Hook,可以極大地簡化響應式開發(fā)。
import { useState, useEffect, useMemo } from 'react';
export enum MediaType {
mobile = 'mobile',
tablet = 'tablet',
pc = 'pc',
}
const useMediaSize = (): MediaType => {
const [width, setWidth] = useState<number>(globalThis.innerWidth);
useEffect(() => {
const handleWindowResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleWindowResize);
// 記得清理事件監(jiān)聽
return () => window.removeEventListener('resize', handleWindowResize);
}, []);
// 使用 useMemo 避免每次渲染都重新運行計算邏輯
const media = useMemo(() => {
if (width <= 640) return MediaType.mobile;
if (width <= 768) return MediaType.tablet;
return MediaType.pc;
}, [width]);
return media;
};
export default useMediaSize;
3. 性能優(yōu)化:防抖與節(jié)流 Hook
A. 防抖 Hook (useDebounce)
常用于搜索框,防止用戶快速輸入時頻繁觸發(fā)請求。
import { useState, useEffect } from 'react';
function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
// 關鍵:在下一次 useEffect 執(zhí)行前清理上一次的定時器
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
}
export default useDebounce;
B. 節(jié)流 Hook (useThrottle)
常用于滾動加載、窗口縮放,確保在規(guī)定時間內只執(zhí)行一次。
import { useState, useEffect, useRef } from 'react';
function useThrottle<T>(value: T, delay: number): T {
const [throttledValue, setThrottledValue] = useState<T>(value);
const lastExecuted = useRef<number>(Date.now());
useEffect(() => {
const now = Date.now();
const remainingTime = delay - (now - lastExecuted.current);
if (remainingTime <= 0) {
// 立即執(zhí)行
setThrottledValue(value);
lastExecuted.current = now;
} else {
// 設置定時器處理剩余時間
const timer = setTimeout(() => {
setThrottledValue(value);
lastExecuted.current = Date.now();
}, remainingTime);
return () => clearTimeout(timer);
}
}, [value, delay]);
return throttledValue;
}
export default useThrottle;
三、 總結:封裝自定義 Hook 的心法
- 抽離狀態(tài)而非僅邏輯:如果一段邏輯只涉及純函數(shù)計算,不需要 Hook;只有涉及 useState 或 useEffect 等狀態(tài)管理時,才有必要封裝 Hook。
- 保持純凈:自定義 Hook 應該只關心邏輯,而不應該直接操作 DOM。
- TS 類型保護:利用泛型 <T> 增強 Hook 的兼容性,讓它能適配各種數(shù)據類型。
到此這篇關于React中Hooks邏輯復用的實現(xiàn)的文章就介紹到這了,更多相關React中Hooks邏輯復用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
antd?table動態(tài)修改表格高度的實現(xiàn)
本文主要介紹了antd?table動態(tài)修改表格高度的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-07-07
react echarts tooltip 區(qū)域新加輸入框編輯保存數(shù)據功能
這篇文章主要介紹了react echarts tooltip 區(qū)域新加輸入框編輯保存數(shù)據功能,大概思路是用一個div包裹echarts, 然后在echarts的同級新建一個div用來用來模擬真實tooltip,通過鼠標移入移出事件控制真實tooltip的顯示與隱藏,需要的朋友可以參考下2023-05-05
react native創(chuàng)建項目常用插件詳解
文章詳細介紹了React Native項目的頁面路徑目錄設計原則、路由管理、狀態(tài)管理、服務層管理、自定義hook和工具函數(shù)的使用方法、適配方案以及樣式排列對齊方式,通過這些原則和方法,可以提高項目的可維護性和可擴展性2025-12-12

