【问题标题】:React Custom useRequest Hook causes MemoryLeakReact 自定义 useRequest Hook 导致内存泄漏
【发布时间】:2021-03-09 20:13:43
【问题描述】:

我正在开发一个使用 自定义挂钩 useRequest 从服务器获取数据的项目。

实现是


const useRequest = ({ url }) => {
  const [isLoading, setIsLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [apiData, setApiData] = React.useState({});

  React.useEffect(() => {
    const abortController = new AbortController();

    fetch(url, {
      headers: headers,
      signal: abortController.signal,
    })
      .then((res) => res.json())
      .then((data) => {
        setIsLoading(false);
        if (data.status_message) {
          throw Error(data.status_message);
        }
        setApiData(data);
      })
      .catch((err) => {
        setError(err);
        setIsLoading(false);
      });

    return function cleanup() {
      abortController.abort();
    };
  }, [url]);
  return { isLoading, apiData, error };
};

export default useRequest;




我不知道为什么,但有时它会引发内存泄漏错误。有人可以帮忙解释为什么会这样吗?

我使用 useRequest 钩子的组件:

1) ItemInfo 组件-

function Item() {
  const { id } = useParams();
  const { path } = useRouteMatch();
  const type = path.split("/")[1];

  const { isLoading, apiData, error } = useRequest({
    url: request.getItemData(id, type),
  });
  if (error) return <NotFound error={error} />;

  if (isLoading) return <Loader />;
  const RowComp = withRow(Row);

  return (
    <div className="itemInfo">
      {apiData && (
        <>
          <Banner data={apiData} />
          <div className="itemInfo__wrapper">
            <div className="itemInfo__overview">
              <h2>Overview</h2>
              <p>{apiData.overview}</p>
            </div>
            <Details details={apiData} />
            <RowComp title="Cast" url={request.getCast(type, id)} />
            {type === "movie" && apiData.belongs_to_collection && (
              <RowComp
                url={request.getCollection(apiData.belongs_to_collection.id)}
                title="Collections"
              />
            )}
            {type === "tv" && apiData.seasons && (
              <Row results={apiData.seasons} title="Seasons" />
            )}
            <RowComp
              url={request.getRecommendations(id, type)}
              title="Recommendations"
            />
          </div>
        </>
      )}
    </div>
  );
}

export default Item;

2) HOC

function withRow(WrappedComponent) {
  const HOC = ({ url, title }) => {
    const { isLoading, apiData } = useRequest({ url });
    const results = apiData.results || apiData.parts || apiData.cast;
    return (
      <>
        {isLoading && <Loader />}
        {results && <WrappedComponent results={results} title={title} />}
      </>
    );
  };
  HOC.propTypes = {
    url: PropTypes.string,
    title: PropTypes.string,
  };
  return HOC;
}

HOC 组件主要记录错误,但有时 ItemInfo 组件也会记录 Memory Leak 错误 提前致谢。

【问题讨论】:

  • 我认为如果请求被取消,.catch 处理程序调用setError,这可能发生在组件已经卸载之后(因为取消发生在卸载时)。您可以在.catch 中添加日志来检查吗?
  • 我确实发现了错误。这是日志DOMException: The user aborted a request. 但是在这个日志之前,有内存泄漏错误。
  • 咦,那日志是从哪里来的?
  • .catch 块,我添加了一个console.log
  • 啊,好的,您是在setError 之前还是之后添加日志?那么这可能是原因吗?

标签: javascript reactjs memory-leaks react-hooks


【解决方案1】:

会发生什么:

1.) 组件卸载。

2.) 效果清理发生(紧接着,同步),abortController.abort(); 被调用。从现在开始,不应在组件上调用 setState

3.) fetch(...)res.json() (?) 抛出异常,Promise 被拒绝

4.) 在微任务中,.catch 回调运行,setErrorsetIsLoading 被调用。由于该组件不再存在,因此引发了您看到的错误。

在我看来,清理 fetch 应该是无声的,所以应该禁止 AbortErrors:

.catch(error => {
   // If the component is cleaned up, and the fetch() is aborted, silently stop as nobody is listening to our error anyways
   if(error.name === "ABORT_ERR") return;
   // In other cases, raise error to component:
});

【讨论】:

  • 是的,我也有这个。这是因为在.catch() 块中调用setState。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-06
  • 2014-06-07
相关资源
最近更新 更多