Реагируйте на крючки. Периодическое использование

Мне нужно периодически получать данные и обновлять их на экране. У меня есть такой код:

const [temperature, setTemperature] = useState();

useEffect(() => {

fetch("urlToWeatherData")
  .then(function(response) {
     if (response.status !== 200) {
      console.log(
        "Looks like there was a problem. Status Code: " + response.status
      );
      return;
    response.json().then(function(data) {
     console.log(data[0].temperature);
     setTemperature(data[0].temperature);

    });
  })
  .catch(function(err) {
    console.log("Fetch Error :-S", err);
  });
 }, []  );

Итак, есть ли какой-нибудь изящный способ запускать его каждые 15 секунд, например? Спасибо!


person Illya Yushchenko    schedule 09.01.2020    source источник


Ответы (2)


Оберните его в интервал и не забудьте вернуть функцию разрыва, чтобы отменить интервал при размонтировании компонента:

useEffect(() => {
  const id = setInterval(() => 
    fetch("urlToWeatherData")
      .then(function(response) {
         if (response.status !== 200) {
          console.log(
            "Looks like there was a problem. Status Code: " + response.status
          );
          return;
        response.json().then(function(data) {
         console.log(data[0].temperature);
         setTemperature(data[0].temperature);
        });
      })
      .catch(function(err) {
        console.log("Fetch Error :-S", err);
      });
  ), 15000);

  return () => clearInterval(id);  
}, []);
person Nicholas Tower    schedule 09.01.2020
comment
Просто добавленное примечание: если вы хотите запустить его немедленно, а не через 15 секунд после инициализации, просто назовите функцию стрелки, передайте ссылку на setInterval(), а затем вызовите ее непосредственно перед возвратом разрыва. - person Patrick Roberts; 09.01.2020
comment
Спасибо вам всем! Я обернул его функцией, а затем просто дважды вызвал, например: getData(); setInterval(getData, 15000); Теперь, похоже, он работает именно так, как должен. - person Illya Yushchenko; 09.01.2020

Чтобы предложить другой подход, вы можете определить собственный хук для извлечения этой функциональности в функцию многократного использования:

const useInterval = (callback, interval, immediate) => {
  const ref = useRef();

  // keep reference to callback without restarting the interval
  useEffect(() => {
    ref.current = callback;
  }, [callback]);

  useEffect(() => {
    // when this flag is set, closure is stale
    let cancelled = false;

    // wrap callback to pass isCancelled getter as an argument
    const fn = () => {
      ref.current(() => cancelled);
    };

    // set interval and run immediately if requested
    const id = setInterval(fn, interval);
    if (immediate) fn();

    // define cleanup logic that runs
    // when component is unmounting
    // or when or interval or immediate have changed
    return () => {
      cancelled = true;
      clearInterval(id);
    };
  }, [interval, immediate]);
};

Тогда вы можете использовать такой крючок:

const [temperature, setTemperature] = useState();

useInterval(async (isCancelled) => {
  try {
    const response = await fetch('urlToWeatherData');
    // check for cancellation after each await
    // to prevent further action on a stale closure
    if (isCancelled()) return;

    if (response.status !== 200) {
      // throw here to handle errors in catch block
      throw new Error(response.statusText);
    }

    const [{ temperature }] = await response.json();
    if (isCancelled()) return;

    console.log(temperature);
    setTemperature(temperature);
  } catch (err) {
    console.log('Fetch Error:', err);
  }
}, 15000, true);

Мы можем предотвратить вызов обратного вызова setTemperature(), если компонент отключен, проверив isCancelled(). Для более общих случаев использования useInterval(), когда обратный вызов зависит от переменных с состоянием, вам следует предпочесть useReducer() или хотя бы используйте функциональную форму обновления _7 _.

person Patrick Roberts    schedule 09.01.2020