背景
我最近把一个相当大的React应用程序升级到了React 18,在大多数情况下它都很棒。其中一个关键的变化是开发中新的双重装载,导致useEffect挂钩都运行两次,这在他们的文档中有明确的记录。
我已经阅读了他们的新效果文档https://beta.reactjs.org/learn/lifecycle-of-reactive-effects尽管它非常详细,但我相信我发现了一个用例,它并没有得到很好的覆盖。
问题
从本质上讲,我遇到的问题是我正在实现与第三方产品的OAuth集成
流程:
->用户单击创建集成
->重定向至"产品登录"诊断树
->使用授权代码重定向回我们的应用程序
->我们点击API完成集成(HTTP POST请求(
现在问题来了,useEffect钩子运行了两次,这意味着我们将两次命中最后一个POST请求,第一次成功,第二次失败,因为集成已经设置好了。
这可能不是一个主要问题,但用户会看到一条错误消息,即使请求有效,感觉只是一个糟糕的模式。
考虑的解决方案
重构以使用按钮
我可能会让用户在登录第三方产品后点击重定向URL上的按钮。这将起作用,并且似乎是React指南所建议的(尽管他们建议的用例不同——https://beta.reactjs.org/learn/you-might-not-need-an-effect#sharing-事件处理程序之间的逻辑(。
这样做的问题是,用户已经单击了一个按钮来创建集成,所以感觉用户体验更差。
忽略重复的API调用
这个问题只是开发中的一个问题,但它仍然有点烦人,感觉像是一个我想进一步探索的问题
代码设置
我已经简化了这个例子的代码,但希望这能大致了解预期代码的功能。
const IntegrationRedirect: React.FC = () => {
const navigate = useNavigate();
const organisationIntegrationsService = useOrganisationIntegrationsService();
// Make call on the mount of this component
useEffect(() => {
// Call the method
handleCreateIntegration();
}, []);
const handleCreateIntegration = async (): Promise<void> => {
// Setup request
const request: ICreateIntegration = {
authorisationCode: ''
};
try {
// Make service call
const setupIntegrationResponse = await organisationIntegrationsService.createIntegration(request);
// Handle error
if (setupIntegrationResponse.data.errors) {
throw 'Failed to setup integrations';
}
// Navigate away on success
routes.organisation.integrations.navigate(navigate);
}
catch (error) {
// Handle error
}
};
return ();
};
我追求的是什么
我正在寻求基于React 18更改的建议来处理这种情况,我觉得尽管这有点特定/小众,但它仍然是一个可行的用例。最好有一种干净的方法来处理这一问题,因为OAuth集成是产品之间集成的常见流程。
您可以将useRef()
与useEffect()
一起用于解决问题
const effectRan = useRef(false)
useEffect(() => {
if (effectRan.current === false) {
// do the async data fetch here
handleCreateIntegration();
}
//cleanup function
return () => {
effectRan.current = true // this will be set to true on the initial unmount
}
}, []);
这是Dave Gray在他的youtube频道上建议的一个变通方法https://www.youtube.com/watch?v=81faZzp18NM