通过 Hook 反应 setInterval - 无效的 hook 调用
React setInterval via Hook - Invalid hook call
我想定期执行一个动作(总是在 4 秒后)。
我以此为例:https://overreacted.io/making-setinterval-declarative-with-react-hooks/
问题:
未捕获的不变违规:无效挂钩调用。钩子只能在函数组件的主体内部调用。这可能由于以下原因之一而发生:
1. React 和渲染器的版本可能不匹配(例如 React DOM)
2. 你可能违反了 Hooks 规则
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;
您的挂钩定义看起来不错,但您无法从组件中定义自定义挂钩。如果你查看文章中的CodeSandbox,你可以看到钩子是在外面定义的。
只需将 useInterval
定义移到 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
应该在组件外部定义,以避免每次渲染都重新创建挂钩(但这不是问题所在)。
我想定期执行一个动作(总是在 4 秒后)。
我以此为例:https://overreacted.io/making-setinterval-declarative-with-react-hooks/
问题:
未捕获的不变违规:无效挂钩调用。钩子只能在函数组件的主体内部调用。这可能由于以下原因之一而发生: 1. React 和渲染器的版本可能不匹配(例如 React DOM) 2. 你可能违反了 Hooks 规则 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;
您的挂钩定义看起来不错,但您无法从组件中定义自定义挂钩。如果你查看文章中的CodeSandbox,你可以看到钩子是在外面定义的。
只需将 useInterval
定义移到 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
应该在组件外部定义,以避免每次渲染都重新创建挂钩(但这不是问题所在)。