簡體   English   中英

使用 AbortController 時清理代碼在 React 中無法正常工作

[英]Clean Up code not works correctly in React when using AbortController

我正在使用自定義useHttp掛鈎從api獲取一些數據,問題是我想在用戶導航到另一個頁面時中止獲取操作並防止出現奇怪的錯誤。 為此,我在我的鈎子中使用AbortController API,每當組件unmounts時,都會觸發該函數。 但是當我的組件渲染時,我會收到一個錯誤,告訴我操作已中止!

掛鈎代碼

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

export const useHttpClient = () => {
   const [isLoading, setIsLoading] = useState(false);
   const [error, setError] = useState();


   const activeHttpRequests = useRef([]);

   const sendRequest = useCallback(async (URL, method = 'GET', body = null, headers = {}) => {
      setIsLoading(true);


      
      const httpAbortController = new AbortController();
      activeHttpRequests.current.push(httpAbortController);

      try {
         const res = await fetch(URL, {method, body, headers, signal: httpAbortController.signal});
         const resData = await res.json();
         
         activeHttpRequests.current = activeHttpRequests.current.filter(reqCtrl => reqCtrl !== httpAbortController)
         console.log(activeHttpRequests)
         
         if(!res.ok) {
            throw new Error(resData.error);
         }
         setIsLoading(false)   
         return resData;
      } catch (error) {
         setIsLoading(false)   
         setError(error.message)
         throw error;
      }
   }, [])

   const clearError = () => {
      setError(null);
   }


   useEffect(() => {
      return () => {
         activeHttpRequests.current.forEach(abortCtrl => abortCtrl.abort());
      };
   }, []);

   return {isLoading, error, clearError, sendRequest}
}

這是我組件中的代碼:

// Modules
import React, { useEffect, useState } from 'react';

// Hooks 
import { useHttpClient } from '../../../helpers/hooks/http-hook';

// Components
import UserList from '../components/user-list/user-list.component';
import ErrorModal from '../../shared/error-modal/error-modal.component';
import Spinner from '../../shared/loading-spinner/spinner.component';


const Users = () => {
   const { isLoading , error , clearError , sendRequest } = useHttpClient();
   const [loadedUsers, setLoadedUsers] = useState();
   
   useEffect(() => {
      const fetchUsers = async () => {
         try {
            const URL = 'http://localhost:5000/api/users';
            const res = await sendRequest(URL);
            setLoadedUsers(res.users);
         } catch (error) {}
      }
      fetchUsers();
   }, [sendRequest])


   return (
      <React.Fragment>
         <ErrorModal error={error} onClear={clearError} />
         { isLoading && <Spinner overlay/> }
         { !isLoading && loadedUsers && <UserList users={loadedUsers} /> }
      </React.Fragment> 
   );
}
export default Users;

每當您的組件重新渲染時,上一次渲染中的 useEffect 的清理效果都會在運行下一次渲染中的效果之前運行。 您在組件掛載時調用fetchUsers() ,這會設置setLoadedUsers ,這將導致重新渲染,這將運行您的清理代碼以嘗試取消不存在的請求。

將您的清理代碼更新為此,它應該可以工作

  useEffect(() => {
      return () => {
        if (activeHttpRequests.current.length) {
          activeHttpRequests.current.forEach(abortCtrl => abortCtrl.abort());
        };
      };
   }, []);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM