useEffect 中异步函数的 React Hook 警告:useEffect 函数必须返回清理函数或不返回任何内容 [英] React Hook Warnings for async function in useEffect: useEffect function must return a cleanup function or nothing
问题描述
我正在尝试 useEffect
示例,如下所示:
useEffect(async() => {尝试 {const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);const json = 等待 response.json();setPosts(json.data.children.map(it => it.data));}赶上(e){控制台错误(e);}}, []);
并且我在控制台中收到此警告.但是我认为清理对于异步调用是可选的.我不确定为什么会收到此警告.链接沙箱示例.
我建议看一下 DanAbramov(React 核心维护者之一)在这里回答:
<块引用>我认为你让它变得比需要的更复杂.
function Example() {const [数据,数据集] = useState(null)useEffect(() => {异步函数 fetchMyAPI() {let response = await fetch('api/data')响应 = 等待 response.json()数据集(响应)}fetchMyAPI()}, [])返回 <div>{JSON.stringify(data)}</div>}
<块引用>
从长远来看,我们将不鼓励这种模式,因为它鼓励竞争条件.比如——在你的通话开始和结束之间可能会发生任何事情,你可能会得到新的道具.相反,我们会推荐 Suspense 来获取数据,它看起来更像
const response = MyAPIResource.read();
<块引用>
并且没有效果.但与此同时,您可以将异步内容移至单独的函数并调用它.
您可以在此处阅读有关实验悬念的更多信息.
如果你想在 eslint 之外使用函数.
function OutsideUsageExample({ userId }) {const [数据,数据集] = useState(null)const fetchMyAPI = useCallback(async () => {let response = await fetch('api/data/' + userId)响应 = 等待 response.json()数据集(响应)}, [userId])//如果userId发生变化,useEffect会再次运行//如果你只想运行一次,只需将数组留空 []useEffect(() => {fetchMyAPI()}, [fetchMyAPI])返回 (<div><div>数据:{JSON.stringify(data)}</div><div><button onClick={fetchMyAPI}>手动获取</button>
)}
如果您将使用 useCallback,请查看其工作原理示例 useCallback.沙盒.
import React, { useState, useEffect, useCallback } from react";导出默认函数 App() {const [计数器,setCounter] = useState(1);//如果计数器改变,那么 fn 将用新的计数器值更新const fn = useCallback(() => {设置计数器(计数器 + 1);}, [柜台]);//如果计数器被改变,那么 fn 将不会被更新并且计数器在 fn 中将始终为 1/*const fnBad = useCallback(() => {设置计数器(计数器 + 1);}, []);*///如果 fn 或 counter 发生变化,则 useEffect 将重新运行useEffect(() => {if (!(counter % 2)) 返回;//如果计数器不是偶数,这将停止循环fn();}, [fn, 计数器]);//这将是无限循环,因为 fn 总是随着新的计数器值而变化/*useEffect(() => {fn();}, [fn]);*/返回 (<div><div>计数器是 {counter}</div><button onClick={fn}>add +1 count</button>
);}
I was trying the useEffect
example something like below:
useEffect(async () => {
try {
const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
const json = await response.json();
setPosts(json.data.children.map(it => it.data));
} catch (e) {
console.error(e);
}
}, []);
and I get this warning in my console. But the cleanup is optional for async calls I think. I am not sure why I get this warning. Linking sandbox for examples. https://codesandbox.io/s/24rj871r0p
I suggest to look at Dan Abramov (one of the React core maintainers) answer here:
I think you're making it more complicated than it needs to be.
function Example() {
const [data, dataSet] = useState<any>(null)
useEffect(() => {
async function fetchMyAPI() {
let response = await fetch('api/data')
response = await response.json()
dataSet(response)
}
fetchMyAPI()
}, [])
return <div>{JSON.stringify(data)}</div>
}
Longer term we'll discourage this pattern because it encourages race conditions. Such as — anything could happen between your call starts and ends, and you could have gotten new props. Instead, we'll recommend Suspense for data fetching which will look more like
const response = MyAPIResource.read();
and no effects. But in the meantime you can move the async stuff to a separate function and call it.
You can read more about experimental suspense here.
If you want to use functions outside with eslint.
function OutsideUsageExample({ userId }) {
const [data, dataSet] = useState<any>(null)
const fetchMyAPI = useCallback(async () => {
let response = await fetch('api/data/' + userId)
response = await response.json()
dataSet(response)
}, [userId]) // if userId changes, useEffect will run again
// if you want to run only once, just leave array empty []
useEffect(() => {
fetchMyAPI()
}, [fetchMyAPI])
return (
<div>
<div>data: {JSON.stringify(data)}</div>
<div>
<button onClick={fetchMyAPI}>manual fetch</button>
</div>
</div>
)
}
If you will use useCallback, look at example of how it works useCallback. Sandbox.
import React, { useState, useEffect, useCallback } from "react";
export default function App() {
const [counter, setCounter] = useState(1);
// if counter is changed, than fn will be updated with new counter value
const fn = useCallback(() => {
setCounter(counter + 1);
}, [counter]);
// if counter is changed, than fn will not be updated and counter will be always 1 inside fn
/*const fnBad = useCallback(() => {
setCounter(counter + 1);
}, []);*/
// if fn or counter is changed, than useEffect will rerun
useEffect(() => {
if (!(counter % 2)) return; // this will stop the loop if counter is not even
fn();
}, [fn, counter]);
// this will be infinite loop because fn is always changing with new counter value
/*useEffect(() => {
fn();
}, [fn]);*/
return (
<div>
<div>Counter is {counter}</div>
<button onClick={fn}>add +1 count</button>
</div>
);
}
这篇关于useEffect 中异步函数的 React Hook 警告:useEffect 函数必须返回清理函数或不返回任何内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!