【问题标题】:Using useEffect hook with "async"将 useEffect 钩子与“异步”一起使用
【发布时间】:2020-07-18 05:34:52
【问题描述】:

如何在反应钩子中清理反应请求。我读到需要进入我的钩子 AbortController 但我不知道如何。我使用 next.js。消除此问题的最佳方法是什么?我收到了这个警告:

警告:无法对未安装的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要解决此问题,请在 useEffect 清理函数中取消所有订阅和异步任务。

这是我获取数据的自定义钩子:

import { useState, useEffect, useCallback } from 'react'
import { MOVIE_API_URL, MOVIE_KEY } from '../../config'

export const useMovieDetailsFetch = (movieId) => {
  const [state, setState] = useState({})
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(false)

  const fetchData = useCallback(async () => {
    setError(false)
    setLoading(true)

    try {
      const movieDetailsEndpoint = `${MOVIE_API_URL}movie/${movieId}?api_key=${MOVIE_KEY}`
      const result = await (await fetch(movieDetailsEndpoint)).json()
      const creditsEndpoint = `${MOVIE_API_URL}movie/${movieId}/credits?api_key=${MOVIE_KEY}`
      const creditsResult = await (await fetch(creditsEndpoint)).json()
      // Filtring in crew for directors only
      const movieDirectors = creditsResult.crew.filter(
        (member) => member.job === 'Director'
      )

      setState({
        ...result,
        movieDirectors,
        actors: creditsResult.cast,
      })
    } catch (error) {
      setError(true)
    }
    setLoading(false)
  }, [movieId])

  useEffect(() => {
   
    fetchData()
  }, [fetchData])

  return [state, loading, error]
}

【问题讨论】:

    标签: javascript reactjs fetch react-hooks next.js


    【解决方案1】:

    以最原始的形式使用abort controller

    const controller = new AbortController();
    const { signal } = controller;
    ...
    
    fetch(url, { signal });
    
    ...
    // abort
    controller.abort();
    

    中止正在运行的fetch 有效挂钩

    useEffect(() => {
      const controller = new AbortController();
      const { signal } = controller;
      fetch(url, { signal });
    
      return () => {
        controller.abort(); // abort on unmount for cleanup
      };
    }, []);
    

    当我需要开发一种取消获取请求的方法时,我发现这个 article 非常有用。

    编辑

    signal 需要添加到 fetch 请求选项对象中。你也可以在 effect 内部定义async fetchData 函数(这很正常),所以它都被封装在了 effect hook 的回调范围内。

    export const useMovieDetailsFetch = (movieId) => {
      const [state, setState] = useState({})
      const [loading, setLoading] = useState(true)
      const [error, setError] = useState(false)
    
      useEffect(() => {
        const controller = new AbortController();
        const { signal } = controller;
    
        const fetchData = async () => {
          setError(false);
          setLoading(true);
    
          try {
            const movieDetailsEndpoint = `${MOVIE_API_URL}movie/${movieId}?api_key=${MOVIE_KEY}`;
            const result = await (
                await fetch(movieDetailsEndpoint, { signal })
              ).json();
            const creditsEndpoint = `${MOVIE_API_URL}movie/${movieId}/credits?api_key=${MOVIE_KEY}`;
            const creditsResult = await (
                await fetch(creditsEndpoint, { signal })
              ).json();
            // Filtring in crew for directors only
            const movieDirectors = creditsResult.crew.filter(
              (member) => member.job === 'Director'
            );
    
            setState({
              ...result,
              movieDirectors,
              actors: creditsResult.cast,
            });
          } catch (error) {
            setError(true);
          }
          setLoading(false);
        }
    
        fetchData();
    
        return () => controller.abort();
      }, [movieId]);
    
      return [state, loading, error];
    }
    

    【讨论】:

    • 我在这个钩子中输入了这个,但它仍然不起作用` useEffect(() => { const controller = new AbortController() const { signal } = controller fetchData({ signal }) return () => { controller.abort() } }, [fetchData])`
    • @KubaKluzniak 需要将信号传递给fetch 函数的选项参数。用建议的解决方案更新了我的答案。
    猜你喜欢
    • 2019-12-29
    • 2019-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-08
    • 1970-01-01
    • 2020-02-20
    • 2021-10-22
    相关资源
    最近更新 更多