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



我想定期执行一个动作(总是在 4 秒后(。

我以这个为例:https://overreacted.io/making-setinterval-declarative-with-react-hooks/

问题:

未捕获的不变冲突:无效的挂钩调用。钩子只能在函数组件的主体内部调用。这可能是由于以下原因之一而发生的:1. 你可能有不匹配的 React 和渲染器版本(比如 React DOM(2.你可能违反了钩子的规则3. 您可能在同一应用程序中有多个 React 副本

我知道 React Hooks 只能在主上下文中使用,而不能在子上下文中使用。这正是我在这里的问题。我想使用一个函数来创建我的间隔。

也许有一种完全不同的方法。

这就是我目前所拥有的,有人可以帮忙吗?

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;

调用 useInterval(...) 时,您在另一个useEffect调用useEffect,这是被禁止的。

最有可能的是,这是您想要的:

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>
      )}
    />
  );
};

注意:useInterval应该在组件外部定义,以避免每次渲染都重新创建钩子(但这不是问题(。

您的钩子定义看起来不错,但您无法从组件中定义自定义钩子。如果你从文章中查看 CodeSandbox,你可以看到钩子是在外面定义的。

只需将useInterval定义移到T3nNews组件之外,它就可以工作(您将能够在其他组件中使用它!

相关内容

  • 没有找到相关文章