亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

搜索
首頁 > web前端 > js教程 > 正文

React中抽象重復(fù)邏輯:利用自定義Hook實(shí)現(xiàn)異步操作與錯(cuò)誤處理的復(fù)用

碧海醫(yī)心
發(fā)布: 2025-10-16 10:28:09
原創(chuàng)
792人瀏覽過

React中抽象重復(fù)邏輯:利用自定義Hook實(shí)現(xiàn)異步操作與錯(cuò)誤處理的復(fù)用

本文將探討如何在react應(yīng)用中,通過自定義hook有效抽象和復(fù)用重復(fù)的異步操作及錯(cuò)誤處理模式。我們將分析常見的加載狀態(tài)、錯(cuò)誤信息及定時(shí)清除邏輯,并展示如何將其封裝成一個(gè)可重用的hook,從而提升代碼的可讀性、可維護(hù)性與開發(fā)效率。

在構(gòu)建復(fù)雜的React應(yīng)用時(shí),開發(fā)者經(jīng)常會遇到管理異步操作(如數(shù)據(jù)加載、表單提交)及其伴隨狀態(tài)(如加載中、錯(cuò)誤信息)的重復(fù)模式。這些模式通常涉及useState、useRef和useCallback等Hook的組合使用。當(dāng)這些邏輯在多個(gè)組件或同一組件的不同部分重復(fù)出現(xiàn)時(shí),代碼會變得冗長、難以維護(hù)且容易出錯(cuò)。

識別重復(fù)模式

讓我們先回顧一個(gè)典型的重復(fù)代碼模式,它用于管理一個(gè)異步操作的加載狀態(tài)和錯(cuò)誤信息,并實(shí)現(xiàn)錯(cuò)誤信息的定時(shí)自動清除:

// 加載所有供應(yīng)商
const [loadingAllVendors, setLoadingAllVendors] = useState<boolean>(true);
const loadAllVendorsErrorTimeout = useRef<NodeJS.Timeout|null>(null);
const [loadAllVendorsError, setLoadAllVendorsError] = useState<string|null>(null);
const handleLoadAllVendorsError = (error: string|null) => {
  if (error) console.error(error);
  setLoadAllVendorsError(error);
};
const loadAllVendorsErrorTime: number = 6;
const timedLoadAllVendorsError = useCallback((error: string, seconds: number) => {
  handleLoadAllVendorsError(error);
  if (loadAllVendorsErrorTimeout.current) clearTimeout(loadAllVendorsErrorTimeout.current);
  loadAllVendorsErrorTimeout.current = setTimeout(() => {
    setLoadAllVendorsError(null);
  }, seconds * 1000)
}, []);

// 加載所有制造商
const [loadingAllManufacturers, setLoadingAllManufacturers] = useState<boolean>(true);
const loadAllManufacturersErrorTimeout = useRef<NodeJS.Timeout|null>(null);
const [loadAllManufacturersError, setLoadAllManufacturersError] = useState<string|null>(null);
const handleLoadAllManufacturersError = (error: string|null) => {
  if (error) console.error(error);
  setLoadAllManufacturersError(error);
};
const loadAllManufacturersErrorTime: number = 6;
const timedLoadAllManufacturersError = useCallback((error: string, seconds: number) => {
  handleLoadAllManufacturersError(error);
  if (loadAllManufacturersErrorTimeout.current) clearTimeout(loadAllManufacturersErrorTimeout.current);
  loadAllManufacturersErrorTimeout.current = setTimeout(() => {
    setLoadAllManufacturersError(null);
  }, seconds * 1000);
}, []);

// 搜索部件
const [searching, setSearching] = useState<boolean>(false);
const searchErrorTimeout = useRef<NodeJS.Timeout|null>(null);
const [searchError, setSearchError] = useState<string|null>(null);
const handleSearchError = (error: string|null) => {
  if (error) console.error(error);
  setSearchError(error);
};
const searchErrorTime: number = 6;
const timedSearchError = useCallback((error: string, seconds: number) => {
  handleSearchError(error);
  if (searchErrorTimeout.current) clearTimeout(searchErrorTimeout.current);
  searchErrorTimeout.current = setTimeout(() => {
    setSearchError(null);
  }, seconds * 1000);
}, []);
登錄后復(fù)制

上述代碼段中,每個(gè)邏輯塊都包含了以下六個(gè)相似的模式:

  1. 一個(gè)表示加載狀態(tài)的boolean類型useState。
  2. 一個(gè)用于存儲定時(shí)器ID的NodeJS.Timeout | null類型useRef。
  3. 一個(gè)表示錯(cuò)誤信息的string | null類型useState。
  4. 一個(gè)處理錯(cuò)誤信息并更新狀態(tài)的函數(shù)。
  5. 一個(gè)默認(rèn)的錯(cuò)誤顯示時(shí)間常量。
  6. 一個(gè)接收錯(cuò)誤信息和持續(xù)時(shí)間,并實(shí)現(xiàn)定時(shí)清除錯(cuò)誤信息的useCallback函數(shù)。

這種重復(fù)性是使用自定義Hook進(jìn)行抽象的絕佳信號。

自定義Hook的解決方案

自定義Hook是React中一種強(qiáng)大的機(jī)制,允許開發(fā)者將組件邏輯提取到可重用的函數(shù)中。通過將上述重復(fù)的加載和錯(cuò)誤處理邏輯封裝到一個(gè)自定義Hook中,我們可以顯著提高代碼的復(fù)用性、可讀性和可維護(hù)性。

我們將創(chuàng)建一個(gè)名為useAsyncOperationState的自定義Hook,它將封裝加載狀態(tài)、錯(cuò)誤狀態(tài)及其相關(guān)的處理邏輯。

降重鳥
降重鳥

要想效果好,就用降重鳥。AI改寫智能降低AIGC率和重復(fù)率。

降重鳥113
查看詳情 降重鳥

實(shí)現(xiàn) useAsyncOperationState Hook

這個(gè)Hook需要管理加載布爾值、錯(cuò)誤字符串以及定時(shí)清除錯(cuò)誤的邏輯。它將接收初始加載狀態(tài)和默認(rèn)的錯(cuò)誤顯示時(shí)間作為參數(shù),并返回所有相關(guān)的狀態(tài)和函數(shù)。

import { useState, useRef, useCallback, useEffect } from 'react';

/**
 * 異步操作狀態(tài)管理Hook的返回接口。
 */
interface AsyncOperationState {
  isLoading: boolean;
  error: string | null;
  setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
  handleError: (error: string | null) => void;
  timedError: (error: string, seconds?: number) => void;
  clearError: () => void;
}

/**
 * useAsyncOperationState
 *
 * 一個(gè)自定義Hook,用于抽象和管理異步操作的加載狀態(tài)、錯(cuò)誤狀態(tài)及定時(shí)清除錯(cuò)誤邏輯。
 *
 * @param initialLoading 初始加載狀態(tài),默認(rèn)為 false。
 * @param defaultErrorTime 錯(cuò)誤信息默認(rèn)顯示時(shí)間(秒),默認(rèn)為 6 秒。
 * @returns 包含加載狀態(tài)、錯(cuò)誤信息及其處理函數(shù)的對象。
 */
function useAsyncOperationState(
  initialLoading: boolean = false,
  defaultErrorTime: number = 6
): AsyncOperationState {
  const [isLoading, setIsLoading] = useState<boolean>(initialLoading);
  const [error, setError] = useState<string | null>(null);
  const errorTimeoutRef = useRef<NodeJS.Timeout | null>(null);

  // 清除錯(cuò)誤信息的函數(shù)
  const clearError = useCallback(() => {
    setError(null);
    if (errorTimeoutRef.current) {
      clearTimeout(errorTimeoutRef.current);
      errorTimeoutRef.current = null;
    }
  }, []);

  // 處理錯(cuò)誤信息并設(shè)置狀態(tài)的函數(shù)
  const handleError = useCallback((err: string | null) => {
    if (err) {
      console.error(err);
    }
    setError(err);
  }, []);

  // 設(shè)置定時(shí)清除錯(cuò)誤信息的函數(shù)
  const timedError = useCallback((err: string, seconds?: number) => {
    handleError(err); // 首先設(shè)置錯(cuò)誤信息
    const duration = seconds !== undefined ? seconds : defaultErrorTime;

    // 如果存在舊的定時(shí)器,先清除
    if (errorTimeoutRef.current) {
      clearTimeout(errorTimeoutRef.current);
    }

    // 設(shè)置新的定時(shí)器
    errorTimeoutRef.current = setTimeout(() => {
      setError(null);
      errorTimeoutRef.current = null; // 清除后將引用置空
    }, duration * 1000);
  }, [handleError, defaultErrorTime]); // 依賴 handleError 和 defaultErrorTime

  // 組件卸載時(shí)清除任何未完成的定時(shí)器,防止內(nèi)存泄漏
  useEffect(() => {
    return () => {
      if (errorTimeoutRef.current) {
        clearTimeout(errorTimeoutRef.current);
      }
    };
  }, []);

  return {
    isLoading,
    error,
    setIsLoading,
    handleError,
    timedError,
    clearError,
  };
}

export default useAsyncOperationState;
登錄后復(fù)制

使用自定義Hook重構(gòu)代碼

現(xiàn)在,我們可以使用useAsyncOperationState Hook來替換原先重復(fù)的邏輯。

import React from 'react';
import useAsyncOperationState from './useAsyncOperationState'; // 假設(shè) Hook 文件名為 useAsyncOperationState.ts

function MyComponent() {
  // 加載所有供應(yīng)商
  const {
    isLoading: loadingAllVendors,
    error: loadAllVendorsError,
    setIsLoading: setLoadingAllVendors,
    handleError: handleLoadAllVendorsError,
    timedError: timedLoadAllVendorsError,
  } = useAsyncOperationState(true); // 初始加載狀態(tài)為 true

  // 加載所有制造商
  const {
    isLoading: loadingAllManufacturers,
    error: loadAllManufacturersError,
    setIsLoading: setLoadingAllManufacturers,
    handleError: handleLoadAllManufacturersError,
    timedError: timedLoadAllManufacturersError,
  } = useAsyncOperationState(true); // 初始加載狀態(tài)為 true

  // 搜索部件
  const {
    isLoading: searching,
    error: searchError,
    setIsLoading: setSearching,
    handleError: handleSearchError,
    timedError: timedSearchError,
  } = useAsyncOperationState(false); // 初始加載狀態(tài)為 false

  // 示例:模擬加載供應(yīng)商數(shù)據(jù)
  const fetchVendors = async () => {
    setLoadingAllVendors(true);
    try {
      // 模擬 API 調(diào)用
      await new Promise(resolve => setTimeout(resolve, 1500));
      // 假設(shè)這里發(fā)生了錯(cuò)誤
      if (Math.random() > 0.5) {
        throw new Error('Failed to load vendors!');
      }
      console.log('Vendors loaded successfully!');
      handleLoadAllVendorsError(null); // 清除錯(cuò)誤
    } catch (err: any) {
      timedLoadAllVendorsError(err.message || '未知錯(cuò)誤', 5); // 錯(cuò)誤顯示 5 秒
    } finally {
      setLoadingAllVendors(false);
    }
  };

  // 示例:模擬搜索部件
  const performSearch = async (query: string) => {
    setSearching(true);
    try {
      await new Promise(resolve => setTimeout(resolve, 1000));
      if (query === 'error') {
        throw new Error('Search failed for "error" query!');
      }
      console.log(`Searching for "${query}" successful!`);
      handleSearchError(null);
    } catch (err: any) {
      timedSearchError(err.message || '搜索失敗');
    } finally {
      setSearching(false);
    }
  };

  return (
    <div>
      <h1>異步操作狀態(tài)管理示例</h1>

      <section>
        <h2>供應(yīng)商數(shù)據(jù)</h2>
        {loadingAllVendors && <p>正在加載供應(yīng)商...</p>}
        {loadAllVendorsError && <p style={{ color: 'red' }}>錯(cuò)誤: {loadAllVendorsError}</p>}
        <button onClick={fetchVendors} disabled={loadingAllVendors}>
          {loadingAllVendors ? '加載中...' : '加載供應(yīng)商'}
        </button>
      </section>

      <section>
        <h2>制造商數(shù)據(jù)</h2>
        {loadingAllManufacturers && <p>正在加載制造商...</p>}
        {loadAllManufacturersError && <p style={{ color: 'red' }}>錯(cuò)誤: {loadAllManufacturersError}</p>}
        <button onClick={() => { /* 模擬加載制造商 */ }} disabled={loadingAllManufacturers}>
          {loadingAllManufacturers ? '加載中...' : '加載制造商'}
        </button>
      </section>

      <section>
        <h2>部件搜索</h2>
        {searching && <p>正在搜索...</p>}
        {searchError && <p style={{ color: 'red' }}>錯(cuò)誤: {searchError}</p>}
        <input type="text" placeholder="輸入搜索詞" />
        <button onClick={() => performSearch('example')} disabled={searching}>
          {searching ? '搜索中...' : '搜索部件'}
        </button>
        <button onClick={() => performSearch('error')} disabled={searching}>
          {searching ? '搜索中...' : '模擬搜索錯(cuò)誤'}
        </button>
      </section>
    </div>
  );
}

export default MyComponent;
登錄后復(fù)制

通過使用useAsyncOperationState,我們成功地將重復(fù)的邏輯抽象出來,使得MyComponent中的代碼變得更加簡潔和專注于業(yè)務(wù)邏輯。

優(yōu)勢與注意事項(xiàng)

優(yōu)勢

  • 代碼復(fù)用性: 將公共邏輯提取到單個(gè)Hook中,避免了在多個(gè)地方復(fù)制代碼。
  • 可讀性: 組件內(nèi)部的代碼更加簡潔,易于理解其核心功能,而無需關(guān)注狀態(tài)管理的細(xì)節(jié)。
  • 可維護(hù)性: 當(dāng)需要修改或優(yōu)化異步操作的狀態(tài)管理邏輯時(shí),只需在一個(gè)地方(自定義Hook內(nèi)部)進(jìn)行更改。
  • 分離關(guān)注點(diǎn): 將UI邏輯和狀態(tài)管理邏輯清晰地分離,提升了代碼的組織結(jié)構(gòu)。
  • 測試性: 自定義Hook可以獨(dú)立于組件進(jìn)行測試,簡化了測試過程。

注意事項(xiàng)

  • Hook命名約定: 自定義Hook的名稱必須以use開頭(例如useAsyncOperationState),這是React Hook的命名約定,也是ESLint等工具識別Hook的依據(jù)。
  • Hook的規(guī)則: 只能在React函數(shù)組件的頂層或自定義Hook中調(diào)用Hook,不能在循環(huán)、條件語句或嵌套函數(shù)中調(diào)用。
  • 依賴數(shù)組: 在useCallback和useEffect中使用正確的依賴數(shù)組至關(guān)重要,以避免不必要的重新渲染或過期閉包問題。在timedError中,handleError和defaultErrorTime是其依賴項(xiàng)。
  • 內(nèi)存泄漏: 對于涉及定時(shí)器或訂閱的Hook,務(wù)必在組件卸載時(shí)進(jìn)行清理(使用useEffect的返回函數(shù)),以防止內(nèi)存泄漏。

總結(jié)

自定義Hook是React中一個(gè)非常強(qiáng)大的特性,它使得抽象和復(fù)用組件邏輯變得前所未有的簡單。通過將重復(fù)的異步操作和錯(cuò)誤處理模式封裝到useAsyncOperationState這樣的自定義Hook中,我們不僅減少了代碼量,還極大地提升了應(yīng)用的可維護(hù)性和可擴(kuò)展性。掌握自定義Hook的使用,是編寫高效、整潔React代碼的關(guān)鍵一步。

以上就是React中抽象重復(fù)邏輯:利用自定義Hook實(shí)現(xiàn)異步操作與錯(cuò)誤處理的復(fù)用的詳細(xì)內(nèi)容,更多請關(guān)注php中文網(wǎng)其它相關(guān)文章!

最佳 Windows 性能的頂級免費(fèi)優(yōu)化軟件
最佳 Windows 性能的頂級免費(fèi)優(yōu)化軟件

每個(gè)人都需要一臺速度更快、更穩(wěn)定的 PC。隨著時(shí)間的推移,垃圾文件、舊注冊表數(shù)據(jù)和不必要的后臺進(jìn)程會占用資源并降低性能。幸運(yùn)的是,許多工具可以讓 Windows 保持平穩(wěn)運(yùn)行。

下載
來源:php中文網(wǎng)
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請聯(lián)系admin@php.cn
最新問題
開源免費(fèi)商場系統(tǒng)廣告
最新下載
更多>
網(wǎng)站特效
網(wǎng)站源碼
網(wǎng)站素材
前端模板
關(guān)于我們 免責(zé)申明 意見反饋 講師合作 廣告合作 最新更新
php中文網(wǎng):公益在線php培訓(xùn),幫助PHP學(xué)習(xí)者快速成長!
關(guān)注服務(wù)號 技術(shù)交流群
PHP中文網(wǎng)訂閱號
每天精選資源文章推送
PHP中文網(wǎng)APP
隨時(shí)隨地碎片化學(xué)習(xí)
PHP中文網(wǎng)抖音號
發(fā)現(xiàn)有趣的

Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號