Execution After Catching Errors in ReactJS Native Firebase – Solved

I’m struggling with an issue in my code where, even after I catch an error ReactJS and return from a function, the code following the catch block still executes. Below are the two functions I’m using:

Error Code:

codeusernameTaken: async (username) => {
const user = await firebase.firestore().collection("uniqueUsers").doc(username).get();
if (user.exists) {
alert("Username is taken. Try again with another username.");
throw new Error('Username is taken. Try again with another username.');
}
},

changeUsername: async (currentUsername, newUsername) => {
try {
var user = Firebase.getCurrentUser();
await Firebase.usernameTaken(newUsername);
} catch (err) {
alert(err.message);
return;
}
await db.collection('uniqueUsers').doc(currentUsername).delete();
await db.collection("users").doc(user.uid).update({username: newUsername});
await db.collection("uniqueUsers").doc(newUsername).set({username: newUsername});
alert("Congratulations! You have successfully updated your username.");
}

In changeUsername, I call usernameTaken, and if the username exists, it should throw an ReactJS error, which I catch in the catch block. However, the code after the catch block still runs, even when I return.

The issue in your code is that you’re not awaiting the usernameTaken function call in changeUsername. Since usernameTaken is an asynchronous function, it needs to be awaited; otherwise, changeUsername will continue executing the remaining code, even if an ReactJS error occurs in usernameTaken.

Correct code:

codeusernameTaken: async (username) => {
const user = await firebase.firestore().collection("uniqueUsers").doc(username).get();
if (user.exists) {
alert("Username is taken. Try again with another username.");
throw new Error('Username is taken. Try again with another username.');
}
},

changeUsername: async (currentUsername, newUsername) => {
try {
const user = Firebase.getCurrentUser();
await Firebase.usernameTaken(newUsername); // Use 'await' here to handle asynchronous error correctly
} catch (err) {
alert(err.message);
return; // Exit the function if an error is caught
}

// Proceed with updating the username if no error is thrown
await db.collection('uniqueUsers').doc(currentUsername).delete();
await db.collection("users").doc(user.uid).update({username: newUsername});
await db.collection("uniqueUsers").doc(newUsername).set({username: newUsername});
alert("Congratulations! You have successfully updated your username.");
}

Explanation:

  1. Adding await to usernameTaken(newUsername):
    • In changeUsername, adding await before Firebase.usernameTaken(newUsername); ensures that the function waits for usernameTaken to complete before moving on to the next line.
    • This way, if usernameTaken throws an error, the catch block in changeUsername will handle it immediately, stopping the function from continuing.
  2. Exiting the Function in the catch Block:
    • If an error is thrown (e.g., the username already exists), catch will capture it, show the alert, and return, effectively ending the function execution.
  3. Proceeding with Updates if No Error Occurs:
    • If usernameTaken completes without errors, the code proceeds to delete the old username and update the new username in the database.

This correction ensures that if usernameTaken throws an error, the rest of changeUsername does not run, avoiding any unintended behavior.

Final Thought:

In troubleshooting asynchronous code, it’s essential to ensure proper handling of await within try-catch blocks to prevent unintended execution of subsequent code. By correctly awaiting functions and handling ReactJS errors, we can create a more reliable and predictable workflow. This approach not only improves code readability but also provides a smoother user experience by effectively managing errors before they cause further issues. Debugging these nuances can be challenging, but understanding async behavior ultimately strengthens code quality and functionality.

Related blog posts