我正在尝试下面的useEffect示例:
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);
}
}, []);
我在控制台得到这个警告。但我认为,对于异步调用,清理是可选的。我不知道为什么我得到这个警告。链接沙盒为例。https://codesandbox.io/s/24rj871r0p
在React提供更好的方法之前,你可以创建一个帮助器useEffectAsync.js:
import { useEffect } from 'react';
export default function useEffectAsync(effect, inputs) {
useEffect(() => {
effect();
}, inputs);
}
现在你可以传递一个async函数:
useEffectAsync(async () => {
const items = await fetchSomeItems();
console.log(items);
}, []);
更新
如果您选择这种方法,请注意这是一种糟糕的形式。当我知道这是安全的时候,我就会这样做,但这总是糟糕的方式和随意的。
悬疑的数据获取,仍处于实验阶段,将解决一些情况。
在其他情况下,您可以将异步结果建模为事件,以便您可以根据组件生命周期添加或删除侦听器。
或者你可以将异步结果建模为一个Observable,这样你就可以根据组件的生命周期订阅和取消订阅。
使用自定义库提供的useAsyncEffect钩子,安全地执行异步代码并在效果中发出请求变得微不足道,因为它使您的代码可自动取消(这只是功能列表中的一件事)。查看带有JSON抓取的Live Demo
import React from "react";
import { useAsyncEffect } from "use-async-effect2";
import cpFetch from "cp-fetch";
/*
Notice: the related network request will also be aborted
Checkout your network console
*/
function TestComponent(props) {
const [cancel, done, result, err] = useAsyncEffect(
function* () {
const response = yield cpFetch(props.url).timeout(props.timeout);
return yield response.json();
},
{ states: true, deps: [props.url] }
);
return (
<div className="component">
<div className="caption">useAsyncEffect demo:</div>
<div>
{done ? (err ? err.toString() : JSON.stringify(result)) : "loading..."}
</div>
<button className="btn btn-warning" onClick={cancel} disabled={done}>
Cancel async effect
</button>
</div>
);
}
export default TestComponent;
同样的演示使用了axios
对于使用React Hooks从外部API中获取,你应该调用一个从useEffect钩子内部的API中获取的函数。
是这样的:
async function fetchData() {
const res = await fetch("https://swapi.co/api/planets/4/");
res
.json()
.then(res => setPosts(res))
.catch(err => setErrors(err));
}
useEffect(() => {
fetchData();
}, []);
我强烈建议你不要在useEffect钩子中定义你的查询,因为它会被无限次地重新渲染。由于不能将useEffect设置为异步,所以可以将其中的函数设置为异步。
在上面所示的例子中,API调用在另一个单独的异步函数中,因此它确保调用是异步的,并且只发生一次。此外,useEffect的依赖数组([])是空的,这意味着它的行为就像React类组件中的componentDidMount一样,它只会在组件被挂载时执行一次。
对于加载文本,你可以使用React的条件渲染来验证你的帖子是否为空,如果是,渲染一个加载文本,否则,显示帖子。当你完成从API获取数据并且post不为空时,else将为真。
{posts === null ? <p> Loading... </p>
: posts.map((post) => (
<Link key={post._id} to={`/blog/${post.slug.current}`}>
<img src={post.mainImage.asset.url} alt={post.mainImage.alt} />
<h2>{post.title}</h2>
</Link>
))}
我看到你已经在使用条件渲染,所以我建议你深入了解它,特别是验证对象是否为空!
如果您需要更多关于使用Hooks使用API的信息,我建议您阅读以下文章。
https://betterprogramming.pub/how-to-fetch-data-from-an-api-with-react-hooks-9e7202b8afcd
https://reactjs.org/docs/conditional-rendering.html
在React提供更好的方法之前,你可以创建一个帮助器useEffectAsync.js:
import { useEffect } from 'react';
export default function useEffectAsync(effect, inputs) {
useEffect(() => {
effect();
}, inputs);
}
现在你可以传递一个async函数:
useEffectAsync(async () => {
const items = await fetchSomeItems();
console.log(items);
}, []);
更新
如果您选择这种方法,请注意这是一种糟糕的形式。当我知道这是安全的时候,我就会这样做,但这总是糟糕的方式和随意的。
悬疑的数据获取,仍处于实验阶段,将解决一些情况。
在其他情况下,您可以将异步结果建模为事件,以便您可以根据组件生命周期添加或删除侦听器。
或者你可以将异步结果建模为一个Observable,这样你就可以根据组件的生命周期订阅和取消订阅。