Reputation: 39
I am working on developing an app on React Native and I am encountering an issue with a useEffect inside a component being run multiple times simultaneously when the shared state from context changes (only once), making the alert to pop up twice. I have been trying to solve this for a while but I can't find the solution. This happens when the state of a variable used in another component is changed in my authContext.
authContext.js:
const [pendingLinkData, setPendingLinkData] = useState(null);
if (signInMethods.includes("password") && !signInMethods.includes("google.com")) {
setPendingLinkData({ email: userEmail, googleCredential });
return;
}
return (
<AuthContext.Provider
value={{
pendingLinkData,
setPendingLinkData,
}}
>
{children}
</AuthContext.Provider>
);
The code in the other component where the useEffect and the component itself re-renders multiple times, causing the useEffect to run simultaneously multiple times and making the alert to pop up more than once:
const { linkAccountWithGoogle, pendingLinkData, setPendingLinkData } = useAuth();
useEffect(() => {
if (!pendingLinkData) return;
Alert.alert(
"Account Exists",
"An account with this email already exists. Do you want to link your Google account?",
[
{
text: "Cancel",
style: "cancel",
onPress: () => {
setPendingLinkData(null); // Reset pending link data
}
},
{
text: "OK",
onPress: () => {
setModalVisible(true); // Proceed with linking
}
}
]
);
}, [pendingLinkData]);
The pendingLinkData is set by the authContext after the user signs in with google, to check if the account should be linked. My expected behaviour would be for that useEffect to run only once when the state changes, but instead, its being run multiple times with the updated pendingLinkData, making the alert to be shown multiple times. I am probably doing something very wrong, but I can't find the why.
Thank you very much for your time
Upvotes: -1
Views: 52
Reputation: 43899
Each time pendingLinkData is set, its value changes, even if the email is the same. You might try checking pendingLinkData.email and putting that in the dependency list, since strings will compare equal.
I don't think your re-render explanation quite makes sense. What I am suggesting is something like:
const { linkAccountWithGoogle, pendingLinkData, setPendingLinkData }
= useAuth();
const email = pendingLinkData?.email;
useEffect(() => {
if (!email) return;
Alert.alert(
"Account Exists",
`An account for ${email} already exists. Do you want to link your Google account?`,
[.......]
);
}, [email]);
Notice that I'm also including the email in the alert message so you can see what you're getting.
If the issue is re-rendering, you would want to move the Alert code up the code tree to something that isn't being destroyed and recreated, or do something to stop the destroy/re-create cycle.
I saw your video. It looks like the second Alert is created before the Cancel action resets pendingLinkData. Possibly you have multiple instances of the component that issues the Alert? It may help to have a "gatekeeper" variable that is set when the Alert is up and is cleared when it is dismissed, and you don't display the Alert if the gatekeeper is set.
Upvotes: 1