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

javascript - Run fetch at regular intervals using react - Stack Overflow

programmeradmin3浏览0评论

I have a grid with different react ponents, all independant - in that they fetch their own data and display it.

I wanted to somehow make them automatically refetch and update every 15 minutes. My first idea was a HOC, but with the newer hooks and functional ponents I tried something using hooks.

So I already was able to create a custom hook - to handle the fetching of data:

const useFetching = (url) => {
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState({});
  const [error, setError] = useState(null);
  const [reload, setReload] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);

        if (!response.ok) {
          throw new Error('Something went wrong');
        }

        const json = await response.json();

        if (json) {
          setData(json);
        }
      } catch (error) {
        setError(error);
      }

      setLoading(false);
    }

    fetchData();

  }, [url, reload]);

  return {
    loading,
    data,
    error
  };
};

Then two ponents using this:

const App1 = () => {
  const {loading, data, error} = useFetching(
    ""
  );

  if (loading || error) {
    return <p>{loading ? "Loading..." : error.message}</p>;
  }

  return (
    <ul>
      {data.hits.map(hit =>
        <li key={hit.objectID}>
          <a href={hit.url}>{hit.title}</a>
        </li>
      )}
    </ul>
  );
};


const App2 = () => {
  const {loading, data, error} = useFetching(
    ""
  );

  if (loading || error) {
    return <p>{loading ? "Loading..." : error.message}</p>;
  }

  return (
    <ul>
      {data.hits.map(hit =>
        <li key={hit.objectID}>
          <a href={hit.url}>{hit.title}</a>
        </li>
      )}
    </ul>
  );
};

ReactDOM.render(<><App1 /><App2/></>, document.getElementById('root'));

This works fine - using the custom hook. So I was thinking something in the lines of:

Set up an interval timer which runs ever 15 minutes and changes the 'reload' state flag - to trigger a refetch and update. Also make sure the interval timer is unset on ponent unload.

To access the state and the setReload method - I placed the timer inside of the useFetching ponent - but that didn't work as it fired up multiple timers. I think I had 14 timers for only two ponents.

I'm really unsure of how to proceed - I would like one timer only handling the refresh of all ponents - at the same time I want the ponents to be independant and not have to share anything with an external timer. It would be fine with one timer per ponent - as long as it properly destroyed when the ponent is unloaded - and it would be nice if this mechanism is built into the useFetching hook.

Is there a much better way to build this - that I'm not thinking of?

Suggestions much appreciated!

I have a grid with different react ponents, all independant - in that they fetch their own data and display it.

I wanted to somehow make them automatically refetch and update every 15 minutes. My first idea was a HOC, but with the newer hooks and functional ponents I tried something using hooks.

So I already was able to create a custom hook - to handle the fetching of data:

const useFetching = (url) => {
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState({});
  const [error, setError] = useState(null);
  const [reload, setReload] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);

        if (!response.ok) {
          throw new Error('Something went wrong');
        }

        const json = await response.json();

        if (json) {
          setData(json);
        }
      } catch (error) {
        setError(error);
      }

      setLoading(false);
    }

    fetchData();

  }, [url, reload]);

  return {
    loading,
    data,
    error
  };
};

Then two ponents using this:

const App1 = () => {
  const {loading, data, error} = useFetching(
    "https://hn.algolia./api/v1/search?query=redux"
  );

  if (loading || error) {
    return <p>{loading ? "Loading..." : error.message}</p>;
  }

  return (
    <ul>
      {data.hits.map(hit =>
        <li key={hit.objectID}>
          <a href={hit.url}>{hit.title}</a>
        </li>
      )}
    </ul>
  );
};


const App2 = () => {
  const {loading, data, error} = useFetching(
    "https://hn.algolia./api/v1/search?query=balls"
  );

  if (loading || error) {
    return <p>{loading ? "Loading..." : error.message}</p>;
  }

  return (
    <ul>
      {data.hits.map(hit =>
        <li key={hit.objectID}>
          <a href={hit.url}>{hit.title}</a>
        </li>
      )}
    </ul>
  );
};

ReactDOM.render(<><App1 /><App2/></>, document.getElementById('root'));

This works fine - using the custom hook. So I was thinking something in the lines of:

Set up an interval timer which runs ever 15 minutes and changes the 'reload' state flag - to trigger a refetch and update. Also make sure the interval timer is unset on ponent unload.

To access the state and the setReload method - I placed the timer inside of the useFetching ponent - but that didn't work as it fired up multiple timers. I think I had 14 timers for only two ponents.

I'm really unsure of how to proceed - I would like one timer only handling the refresh of all ponents - at the same time I want the ponents to be independant and not have to share anything with an external timer. It would be fine with one timer per ponent - as long as it properly destroyed when the ponent is unloaded - and it would be nice if this mechanism is built into the useFetching hook.

Is there a much better way to build this - that I'm not thinking of?

Suggestions much appreciated!

Share Improve this question edited Mar 18, 2022 at 9:20 VLAZ 29.1k9 gold badges62 silver badges84 bronze badges asked Dec 2, 2019 at 13:11 YonderYonder 7393 gold badges14 silver badges28 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 7

You need a useInterval hook. This post explains exactly why and how: https://overreacted.io/making-setinterval-declarative-with-react-hooks/

Since useFetch encapsulates the fetching logic for a single ponent, makes sense that each ponent manages it's own interval. You can achieve that by declaring on mount an interval which will be triggered fifteen minutes later.

useEffect(() =>{
    let interval = setInterval(() => setReload(true), (1000 * 60 * 15))
    //destroy interval on unmount
    return () => clearInterval(interval)
})

More about useEffect (including effect cleanup as above) in the documentation.

发布评论

评论列表(0)

  1. 暂无评论