使用React 18 useEffect钩子运行两次来处理OAuth



背景

我最近把一个相当大的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

最新更新