我开始使用新的和闪亮的钩子构建一些新组件。但是我在组件中使用了很多异步API调用,在数据获取时,我还显示了一个加载旋转器。因此,据我了解,这应该是正确的:
const InsideCompontent = props => {
const [loading, setLoading] = useState(false);
useEffect(() => {
...
fetchData()
...
},[])
function fetchData() {
setFetching(true);
apiCall().then(() => {
setFetching(false)
})
}
}
所以这只是我最初对可能如何工作的想法。只是一个小例子。但是,如果亲本组件现在的条件更改了该组件在异步调用完成之前将其卸下的情况会发生什么。
在我在API回调中调用setFetching(false)
之前,是否有某种检查是否可以检查组件是否仍在安装?
还是我在这里错过了什么?
这是有效的示例:https://codesandbox.io/s/1o0pm2j5yq
编辑:这里没有真正的问题。您可以在这里尝试一下:https://codesandbox.io/s/1o0pm2j5yq
错误来自其他事物,因此,使用挂钩,您不需要在进行状态更改之前检查组件是否已安装。
使用它的另一个原因:)
您可以使用useRef
钩存储您喜欢的任何可变值,因此您可以在卸载组件时使用它将变量isMounted
切换到false
,并检查此变量是否为true
在尝试更新状态之前。
示例
const { useState, useRef, useEffect } = React;
function apiCall() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Foo");
}, 2000);
});
}
const InsideCompontent = props => {
const [state, setState] = useState({ isLoading: true, data: null });
const isMounted = useRef(true);
useEffect(() => {
apiCall().then(data => {
if (isMounted.current) {
setState({ isLoading: false, data });
}
});
return () => {
isMounted.current = false
};
}, []);
if (state.isLoading) return <div>Loading...</div>
return <div>{state.data}</div>;
};
function App() {
const [isMounted, setIsMounted] = useState(true);
useEffect(() => {
setTimeout(() => {
setIsMounted(false);
}, 1000);
}, []);
return isMounted ? <InsideCompontent /> : null;
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
这是用于获取我们内部使用的数据的钩子。它还允许数据获取后操纵数据,如果在呼叫完成之前进行另一个呼叫,将丢弃数据。
https://www.npmjs.com/package/use-data-hook
(如果您不想要整个软件包,也可以包括代码)
^也可以通过简单地删除类型来转换为JavaScript。
它受到本文的启发,但具有更多功能,因此,如果您不需要数据操作,则可以始终在该文章中使用该解决方案。
假设这是您遇到的错误:
警告:无法在未填充组件上执行React状态更新。这是一个无操作,但表示您的应用程序中的内存泄漏。要修复,请在使用效率清理功能中取消所有订阅和异步任务。
React抱怨并同时暗示您。如果必须卸下组件,但是有一个未出色的网络请求,则应取消。从useEffect
内返回功能是执行所需清理(文档)的一种机制。
使用setTimeout
构建示例:
const [fetching, setFetching] = useState(true);
useEffect(() => {
const timerId = setTimeout(() => {
setFetching(false);
}, 4000);
return () => clearTimeout(timerId)
})
如果组件在回调发生之前卸下,则清除计时器,并且不会调用setFetching
。