Как я могу исправить "useEffect имеет отсутствующую зависимость" в пользовательском хуке - PullRequest
1 голос
/ 16 октября 2019

Я использую пользовательский хук для получения некоторых данных из API для использования в наборе компонентов функций React. Однако esLint выдает прекрасное предупреждение:

У React Hook useEffect отсутствует зависимость: 'fetchFromAPI'. Либо включите его, либо удалите массив зависимостей.

Я не думал, что это зависимость, так как она находится внутри useFetch(). Мне нужно сделать это, так как я использую await. Что я делаю неправильно? Можно ли просто отключить предупреждение для этой строки? Или я должен использовать более канонический синтаксис?

function useFetch (url) {
  const [data, setData] = useState(null);

  async function fetchFromAPI() {
    const json = await( await fetch(url) ).json();
    setData(json);
  }

  useEffect(() => {fetchFromAPI()},[url]);

  return data;
};

export {
  useFetch
};

Ответы [ 4 ]

2 голосов
/ 16 октября 2019

Объявите его вне вашего пользовательского эффекта, передав url в качестве параметра и return json для установки внутри useEffect

async function fetchFromAPI(url) {
    const json = await( await fetch(url) ).json();
    return json
}

function useFetch (url) {
  const [data, setData] = useState(null);

  useEffect(() => {
      setData(fetchFromAPI(url))
  },[url]);

  return data;
};

или непосредственно внутри useEffect

function useFetch (url) {
  const [data, setData] = useState(null);

  useEffect(() => {
      async function fetchFromAPI() {
         const json = await( await fetch(url) ).json();
         return json
      }
      setData(fetchFromAPI())
  },[url]);

  return data;
};
1 голос
/ 16 октября 2019
async function fetchFromAPI(url) {
  return ( await fetch(url) ).json();
}

function useFetch (url) {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetchFromAPI(url).then(setData);
  }, [url, setData, fetchFromAPI]);

  return data;
};

export {
  useFetch
};
  1. Вы можете немного изменить, а затем извлечь fetchFromAPI, так как он не создается каждый раз при вызовах useFetch, также это хорошо для одиночной ответственности.
  2. Если вы хорошо понимаете этот кодКонечно, вы можете либо отключить линтинг для этой текущей строки, либо добавить остальные параметры setData и fetchFromAPI. И именно в таком порядке. Потому что при повторном рендеринге сравнение параметров начинается с первого параметра до последнего, и лучше размещать наиболее измененный параметр на первом месте, чтобы не проверять неизмененный параметр каждый раз, когда изменяется следующий, поэтому, если он был изменен в первый раз, useEffect ненужно проверить остальные и вызвать переданную функцию раньше
1 голос
/ 16 октября 2019

Просто переместите свою функцию внутрь useEffect, и все будет хорошо:

import { useState, useEffect } from "react";

function useFetch(url) {
  const [data, setData] = useState(null);

  useEffect(() => {
    async function fetchFromAPI() {
      const json = await (await fetch(url)).json();
      setData(json);
    }
    fetchFromAPI();
  }, [url]);

  return data;
}

export { useFetch };

https://codesandbox.io/s/clever-cdn-8g0me

1 голос
/ 16 октября 2019

Я предлагаю вам определить асинхронную функцию внутри самого useEffect:

function useFetch (url) {
  const [data, setData] = useState(null);
  useEffect(() => {
    async function fetchFromAPI() {
      const json = await( await fetch(url) ).json();
      setData(json);
    }
    fetchFromAPI()
  },[url]);

  return data;
};

Вы можете взглянуть на действительный пример из doc faqs , который использует асинхронную функцию внутри самого useEffect:

function ProductPage({ productId }) {
  const [product, setProduct] = useState(null);

  useEffect(() => {
    // By moving this function inside the effect, 
    // we can clearly see the values it uses.
    async function fetchProduct() {
      const response = await fetch('http://myapi/product' + productId);
      const json = await response.json();
      setProduct(json);
    }

    fetchProduct();
  }, [productId]); // ✅ Valid because our effect only uses productId
  // ...
}
...