使用 react 定期运行 fetch

Posted

技术标签:

【中文标题】使用 react 定期运行 fetch【英文标题】:Run fetch at regular intervals using react 【发布时间】:2020-03-27 02:34:04 【问题描述】:

我有一个包含不同反应组件的网格,它们都是独立的 - 因为它们获取自己的数据并显示它。

我想以某种方式让它们每 15 分钟自动重新获取和更新一次。我的第一个想法是 HOC,但使用更新的钩子和功能组件我尝试使用钩子。

所以我已经能够创建一个自定义挂钩 - 来处理数据的获取:

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
  ;
;

然后两个组件使用这个:

const App1 = () => 
  const loading, data, error = useFetching(
    "https://hn.algolia.com/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.com/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'));

这很好用 - 使用自定义挂钩。所以我在想一些事情:

设置一个每隔 15 分钟运行一次的间隔计时器并更改“重新加载”状态标志 - 以触发重新获取和更新。还要确保在组件卸载时未设置间隔计时器。

要访问状态和 setReload 方法 - 我将计时器放置在 useFetching 组件中 - 但由于它启动了多个计时器,因此这不起作用。我想我只有两个组件有 14 个计时器。

我真的不确定如何继续 - 我希望一个计时器只处理所有组件的刷新 - 同时我希望组件是独立的,并且不必与外部计时器共享任何内容。每个组件有一个计时器就可以了——只要在卸载组件时正确销毁它——如果这个机制内置到 useFetching 钩子中会很好。

有没有更好的方法来构建它 - 我没有想到?

非常感谢您的建议!

【问题讨论】:

【参考方案1】:

由于useFetch 封装了单个组件的获取逻辑,因此每个组件管理自己的间隔是有意义的。您可以通过在挂载时声明一个间隔来实现,该间隔将在十五分钟后触发。

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

更多关于useEffect(包括上面的效果清理)in the documentation。

【讨论】:

哈哈是的。清理就在那里。感谢您增强答案! 谢谢!使用 useEffect(() => const interval = setInterval(() => setReload(state => !state), 3000); console.log('setup interval' + interval); return () => clearInterval(interval) ; , []) 有用!谢谢!所以我每次都必须切换重新加载 - 我只需要运行一次。【参考方案2】:

你需要一个useInterval 钩子。这篇文章准确地解释了为什么以及如何:https://overreacted.io/making-setinterval-declarative-with-react-hooks/

【讨论】:

这篇文章真的很棒,谢谢!不知道为什么,但使用 setInterval 效果很好 - 也许是因为我一直在运行相同的东西并使用当前状态

以上是关于使用 react 定期运行 fetch的主要内容,如果未能解决你的问题,请参考以下文章

React内部useEffect中使用fetch的问题

React Fetch:获取json结果但显示网络错误

Android上的React Native,带有fetch的ajax调用失败

如何使用 React.js 中的 Fetch API 将数据发布到数据库

十React 获取服务器数据: axios插件 fetch-jsonp插件的使用

将 fetch 与 Express、React、cors、cookie 一起使用 - “Access-Control-Allow-Origin”标头