简体   繁体   English

通过 Hook 反应 setInterval - 无效的钩子调用

[英]React setInterval via Hook - Invalid hook call

I want to perform an action periodically (always after 4 seconds).我想定期执行一个操作(总是在 4 秒后)。

I have taken this as example: https://overreacted.io/making-setinterval-declarative-with-react-hooks/我以此为例: https : //overreacted.io/making-setinterval-declarative-with-react-hooks/

Problem:问题:

Uncaught Invariant Violation: Invalid hook call.未捕获的不变违规:无效的挂钩调用。 Hooks can only be called inside of the body of a function component.钩子只能在函数组件的主体内部调用。 This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app这可能是由于以下原因之一而发生的: 1. 你可能有不匹配的 React 版本和渲染器(例如 React DOM) 2. 你可能违反了 Hooks 规则 3. 你可能有多个 React 副本同一个应用

I know that React Hooks can only be used in the main context and not in sub-contexts.我知道 React Hooks 只能在主上下文中使用,不能在子上下文中使用。 And exactly this is my problem here.这正是我的问题。 I want to use a function to create my interval.我想使用一个函数来创建我的间隔。

Maybe there is a complete different approach.也许有一种完全不同的方法。

That's what I have so far, can someone help?这就是我到目前为止所拥有的,有人可以帮忙吗?

 import React, { useState, useEffect, useRef } from 'react'; import { List } from 'antd'; import axios from 'axios'; import isRequestPerformOk from '../../utils/isRequestPerformOk'; import assertChain from '../../utils/assertChain'; import getConfigs from '../../utils/getConfigs'; const useInterval = (callback, delay) => { const savedCallback = useRef(); // Remember the latest function. useEffect(() => { savedCallback.current = callback; }, [callback]); // Set up the interval. // eslint-disable-next-line useEffect(() => { function tick() { savedCallback.current(); } if (delay !== null) { const id = setInterval(tick, delay); return () => clearInterval(id); } }, [delay]); }; const T3nNews = () => { const [data, setData] = useState({ entries: [] }); const configs = getConfigs(); const updateDataFn = async (uri) => { const res = await axios.get(uri); const entriesList = assertChain(res, 'data.entries') ? res.data.entries : []; setData({ entries: entriesList }); }; const setUpDataFn = (uri) => { useInterval(() => { if (isRequestPerformOk() || true) { updateDataFn(uri); } }, 4000); updateDataFn(uri); }; setUpDataFn(configs.uris.t3nRSS); const createMarkup = description => ({ __html: description }); return ( <List className="t3nNews" itemLayout="horizontal" dataSource={data.entries} renderItem={item => ( <List.Item> <List.Item.Meta className="meta" title={item.title} description={ <p dangerouslySetInnerHTML={createMarkup(item.description)} /> } /> </List.Item> )} /> ); }; export default T3nNews;

You are calling useEffect inside another useEffect when calling useInterval(...) , which is forbidden.要调用useEffect另一个里面useEffect打电话时useInterval(...)这是被禁止的。

Most likely, this is what you want instead:最有可能的是,这就是您想要的:

const T3nNews = () => {
  const [data, setData] = useState({ entries: [] });
  const configs = getConfigs();

  const updateDataFn = async (uri) => {
    const res = await axios.get(uri);
    const entriesList = assertChain(res, 'data.entries')
      ? res.data.entries
      : [];
    setData({ entries: entriesList });
  };

  useInterval(() => {
    if (isRequestPerformOk() || true) {
      updateDataFn(configs.uris.t3nRSS);
    }
  }, 4000);

  const createMarkup = description => ({ __html: description });
  return (
    <List
      className="t3nNews"
      itemLayout="horizontal"
      dataSource={data.entries}
      renderItem={item => (
        <List.Item>
          <List.Item.Meta
            className="meta"
            title={item.title}
            description={
              <p dangerouslySetInnerHTML={createMarkup(item.description)} />
            }
          />
        </List.Item>
      )}
    />
  );
};

Note: useInterval should be defined outside of the component, to avoid recreating the hook every render (but that's not the issue).注意: useInterval应该在组件之外定义,以避免在每次渲染时重新创建钩子(但这不是问题)。

Your hook definition looks fine, but you can't define a custom hook from within a component.您的钩子定义看起来不错,但您不能从组件内定义自定义钩子。 If you look at the CodeSandbox from the article, you can see the hook is defined outside.如果你看文章中的CodeSandbox ,你可以看到钩子是在外面定义的。

Just move the useInterval definition outside the T3nNews component and it'll work (and you'll be able to use it in other components!).只需将useInterval定义移到T3nNews组件之外,它就会起作用(并且您将能够在其他组件中使用它!)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM