最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using useEffect hook with "async" - Stack Overflow

programmeradmin0浏览0评论

How to clean up react request in react hooks. I read that in need to enter in my hook AbortController but I don't know how. I using next.js. What are best methods to eliminate this problem ? And I get this warning:

Warning: can't perform a React state update on an unmounted ponent. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

This is my custom hook to fetch data:

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]
}

How to clean up react request in react hooks. I read that in need to enter in my hook AbortController but I don't know how. I using next.js. What are best methods to eliminate this problem ? And I get this warning:

Warning: can't perform a React state update on an unmounted ponent. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

This is my custom hook to fetch data:

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]
}
Share Improve this question edited Jul 25, 2020 at 8:42 marc_s 755k184 gold badges1.4k silver badges1.5k bronze badges asked Apr 6, 2020 at 8:52 klixoklixo 4522 gold badges8 silver badges19 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 7

Using an abort controller, in its rawest form:

const controller = new AbortController();
const { signal } = controller;
...

fetch(url, { signal });

...
// abort
controller.abort();

To abort an in-flight fetch in effect hook

useEffect(() => {
  const controller = new AbortController();
  const { signal } = controller;
  fetch(url, { signal });

  return () => {
    controller.abort(); // abort on unmount for cleanup
  };
}, []);

I found this article very informative when I needed to develop a way to cancel fetch requests.

The signal needs to be added to the fetch requests options object. You can also define the async fetchData function inside the effect (this is normal), so it's all enclosed in the effect hook's callback scope.

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];
}
发布评论

评论列表(0)

  1. 暂无评论