嗨,我在React中遇到useEffect
钩子的问题。下面的代码按应有的方式工作,但是es-lint建议我需要在useEffect
的依赖项数组中提供依赖项。
// eslint-disable-next-line react-hooks/exhaustive-deps
的代码export default function UsersList() {
const [users, setUsers] = useState<User[]>([]);
const { setError } = useContext(errorContext);
const { isLoading, setIsLoading } = useContext(globalContext);
useEffect(() => {
if (users.length < 1) {
fetchUsers();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
async function fetchUsers () {
try {
setIsLoading(true);
const fetchedUsers = await api.getUsers();
setUsers(fetchedUsers);
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
}
}
我试图这样写,代码触发了一个无限循环..(因为状态在函数内部不断变化,并且由于声明的依赖性而每次都触发useEffect
)
useEffect(() => {
async function fetchUsers () {
try {
setIsLoading(true);
const fetchedUsers = await api.getUsers();
setUsers(fetchedUsers);
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
}
if (users.length < 1) {
fetchUsers();
}
}, [setIsLoading, setError, users]);
我还尝试将fetchUsers()
放在依赖项数组中,但这没有效果。
在安装组件时无需使用// eslint-disable-next-line react-hooks/exhaustive-deps
时如何正确设置异步调用?
答案 0 :(得分:2)
您的fetchUsers
函数将使用每个渲染触发使用效果来重新创建自己。您必须使用useCallback
将其包装在渲染器中,以使其参考保持不变,请参见https://reactjs.org/docs/hooks-reference.html#usecallback
此外,为确保只调用一次useEffect(在第一次渲染发生时),我们可以使用useRef存储一个布尔值,这将防止useEffect无限循环
export default function UsersList() {
const [users, setUsers] = useState<User[]>([]);
const { setError } = useContext(errorContext);
const { isLoading, setIsLoading } = useContext(globalContext);
const fetchUsers = useCallback(async function () {
try {
setIsLoading(true);
const fetchedUsers = await api.getUsers();
setUsers(fetchedUsers);
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
}, [setIsLoading, setUsers, setError]);
// Added a ref here to ensure that we call this function only once in initial render
// If you need to refetch the users on error, just call fetchUsers
const isFetchedRef = useRef(false);
useEffect(() => {
if (!isFetchedRef.current) {
isFetchedRef.current = true;
fetchUsers();
}
}, [isLoading, fetchUsers]);
}