繁体   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