- Published on
useAsyncEffect
- Authors

- Name
- 李丹秋
基础用法
import { useAsyncEffect } from 'front-base-hooks';
import React, { useState } from 'react';
function mockCheck(): Promise<boolean> {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, 3000);
});
}
export default () => {
const [pass, setPass] = useState<boolean>();
useAsyncEffect(async () => {
setPass(await mockCheck());
}, []);
return (
<div>
{pass === undefined && 'Checking...'}
{pass === true && 'Check passed.'}
</div>
);
};
如果我们直接在Effect中使用async例如
const UsersComponent = () => {
const [users, setUsers] = useState([]);
const [usersLoading, setUsersLoading] = useState(false);
useEffect(async () => {
setUsersLoading(true);
const result = await getUsers();
setUsers(result);
setUsersLoading(false);
}, []);
return (
<div>
<h1>Users</h1>
<div>
{users.map((user) => (
<div key={user.id}>{user.username}</div>
))}
</div>
</div>
);
};
会提醒useEffect must not return anything besides a function, which is used for clean-up这样的错误
查看useEffect源码得出,useEffect传递的回调函数,返回值必须限定为void或者Destructor,不能是Promise或者迭代器
type EffectCallback = () => (void | Destructor)
type Destructor = () => void | { [UNDEFINED_VOID_ONLY]: never }
源码
import type { DependencyList } from 'react';
import { useEffect } from 'react';
import { isFunction } from '../utils';
function isAsyncGenerator(
val: AsyncGenerator<void, void, void> | Promise<void>,
): val is AsyncGenerator<void, void, void> {
return isFunction(val[Symbol.asyncIterator]);
}
function useAsyncEffect(
effect: () => AsyncGenerator<void, void, void> | Promise<void>,
deps?: DependencyList,
) {
useEffect(() => {
const e = effect();
let cancelled = false;
async function execute() {
if (isAsyncGenerator(e)) {
// eslint-disable-next-line no-constant-condition
while (true) {
const result = await e.next();
if (result.done || cancelled) {
break;
}
}
} else {
await e;
}
}
execute();
return () => {
cancelled = true;
};
}, deps);
}
export default useAsyncEffect;
所以解决方案就是自己再包一层异步函数,然后再执行