Я использую перехватчик useEffect () в React для получения данных с интервалом каждые пять секунд. Когда мое приложение загружается впервые, запрос начальной выборки занимает пять секунд, потому что он находится в функции setInterval (). ...

0
AMP_035 12 Фев 2021 в 07:49

5 ответов

Лучший ответ

Здесь важно отметить, что ваша функция updateData должна возвращать обещание заставить await работать, тогда ваша вышеупомянутая логика будет работать идеально. Он будет ждать, пока первый вызов API не будет завершен, прежде чем перейти ко второй строке.

    useEffect(() => {
    await updateData(id, state, setState);
    const interval = setInterval(async () => {
      if (id) {
        await updateData(id, state, setState); // API call
      }
    }, 5000);

    
    //update function would be like:
    function updateData(id, state, setState) {
      ...
      return API.get("/url");
    }
  }, []);
1
Abdullah Saud 12 Фев 2021 в 06:20

Вы можете использовать значение времени вне хука useEffect. Увеличивайте его каждые 5 секунд и передайте как второй аргумент useEffect. Всякий раз, когда это значение времени изменяется, UseEffect запускается, и он запускает функцию внутри него.

const [timeInterval, setTimeInterval] = useState(0);

setTimeout(() => {
  setTimeInterval(timeInterval + 1);
}, 5000);

useEffect(() => {
  await updateData(id, state, setState); // API call
}, [timeInterval]);
1
smnth90 12 Фев 2021 в 05:17

Я бы использовал два вызова useEffect(): один для 5-секундного опроса и один, который запускается только один раз (с пустым массивом зависимостей). Что-то вроде этого:

// Make API call once
useEffect(() => {
  const live = true;
  if (id) {
     await updateData(id, state, setState, live);
  }
  return () => { live = false; }
}, []);

// Make API call on a 5 second interval
useEffect(() => {
  const live = true;
  const interval = setInterval(async () => {
    if (id) await updateData(id, state, setState, live);
  }, 5000);
  return () => {
    live = false;
    clearInterval(interval);
  }
}, [lensName, state, setState]);

Также обратите внимание, что вам понадобится какой-то флаг, чтобы ваша функция updateData() знала, смонтирован ли компонент. Если он размонтируется, вы не просто хотите отменить интервал, вам также следует избегать вызова setState().

1
Daniel Bank 12 Фев 2021 в 05:17

Вы можете добавить еще один useEffect без зависимости от вызова API при первой загрузке страницы. Однако лучше показать логику updateData, чтобы мы знали, что вы хотите сделать.

// Call api when first load
useEffect(() => {
  await updateData(id, state, setState);
}, [])

// After, every five seconds to call api
useEffect(() => {
  const interval = setInterval(async () => {
    if (id) {
      await updateData(id, state, setState); // API call 
    }
  }, 5000);

  return () => {
    clearInterval(interval);
  };
}, [lensName, state, setState])
1
bcjohn 12 Фев 2021 в 05:22

Следующее решение отлично работает, измените его в соответствии с вашими потребностями:

function App() {
  const [count, setCount] = useState(0);

  const myDummyApi = async () => {
    for (let i = 0; i < 10 ** 9; i++) {
      const val = i;
    }
    return { data: "some data" };
  };

  useEffect(() => {
    if (count === 0) { // condition for checking if the API call being made is initial one or not.
      myDummyApi().then((data) => {
        setCount(count + 1);
      });
    } else {
      const timer = setTimeout(() => {
        myDummyApi().then((data) => {
          setCount(count + 1);
          clearTimeout(timer);
        });
      }, 5000);
    }
  }, [count]);

  return (
    <div className="App">
      <span>{`Api Call ${count}`}</span>
    </div>
  );
}

Полный код можно найти здесь, в песочнице < / а>.

Пояснение:

  1. сделать первоначальный вызов API
  2. после того, как обещание разрешено, установите состояние и увеличьте счетчик, затем компонент снова отобразит
  3. после этого, поскольку count > 0 вызов API будет выполняться только после таймаута 5 секунд.
1
Shyam Mittal 12 Фев 2021 в 05:44
66166479