我正在开发一个组件,我从 URL 读取查询参数并在 useEffect 中发布请求,由于严格模式,这会执行两次。该请求是非幂等的,处理这种情况的最佳方法是什么?
我正在考虑维护一个包含请求是否已执行的引用,如果请求已执行则不执行该请求。
如果您希望请求真正只在应用程序的每个生命周期运行一次,您可以跟踪请求是否以顶级变量开始。听起来太简单了,但确实满足要求。
这也在 react.dev
中推荐let didInit = false;
function App() {
useEffect(() => {
if (!didInit) {
didInit = true;
// ✅ Only runs once per app load
loadDataFromLocalStorage();
checkAuthToken();
}
}, []);
// ...
}
在处理
code
查询字符串参数作为 OAuth2.0 response_type=code
响应处理的一部分时,我遇到了类似的问题。我想从查询字符串中清除 code
,但是当我的组件作为 React 18 新的 StrictMode
行为的一部分重新安装时,我不会有令牌响应或 code
查询字符串,所以第二次安装我的组件时,它看起来像是一个新负载,我应该重定向到我的登录页面。
useRef
也有类似的效果,但不知何故感觉更hacky。我想是因为它不能保证让我的代码真正在每次页面加载时只运行一次的相同效果。
文档建议使用清理功能。清理函数不是阻止它触发两次,而是恢复第一次执行的效果,这样看起来效果就好像只运行了一次。
例如,
useEffect( () => {
const dialog = dialogRef.current;
dialog.showModal();
// This will run after the first execution and close the modal that was just opened.
// Then the second execution will re-open it, and it will remain open.
return () => dialog.close();
}, [] );
我期望的解决方案是使用反应参考。它将与组件外部的变量一起使用,但我更喜欢在其内部拥有特定于组件的任何逻辑。
确保立即设置 ref,而不是等待请求完成 - 否则,它将在 React 开发环境中运行两次。
export const MyComponent = () => {
const initialRequestPerformed = React.useRef<boolean>(false);
useEffect(() => {
if (initialRequestPerformed.current) {
return;
}
initialRequestPerformed.current = true;
// send request
}, []);
return <></>
}