JavaScript: cannot catch error from an async function - javascript

handleEmailSubmit function doesn't catch any errors even if loginWithEmail function throws an error.
Probably my lack of understanding of async functions.
i want your help. thank you.
Login.tsx
const Login: React.FC = () => {
const [errorMsg, setErrorMsg] = useState<string>('');
const history = useHistory();
const handleEmailSubmit = useCallback(async (e) => {
e.preventDefault();
const { email, password } = e.target.elements;
loginWithEmail(email.value, password.value)
.then(() => {
history.push('/');
})
.catch((error) => {
// this block isn't called!
setErrorMsg(error.message);
});
}, []);
return (
<>
<h2>Login</h2>
<form onSubmit={handleEmailSubmit}>
<InputGroup>
<label htmlFor="email">Email</label>
<TextField
id="email"
name="email"
type="email"
/>
</InputGroup>
<InputGroup>
<label htmlFor="password">Password</label>
<TextField
id="password"
name="password"
type="password"
/>
</InputGroup>
<Button type="submit">
้€ไฟกใ™ใ‚‹
</Button>
</form>
</>
);
}
loginWithEmail definition
import axios from 'axios';
// firebase
import 'firebase/auth';
import firebase from 'firebase/app';
export const loginWithEmail = async (
email: string,
password: string
): Promise<void> => {
app
.auth()
.signInWithEmailAndPassword(email, password)
.then((userCredential) => {
userCredential.user?.getIdToken(true).then((token: string) => {
axios
.get('https://dev.myserver.com/api/v1/users/auth', {
headers: { Authorization: `Bearer ${token}` },
})
.catch((error) => {
app.auth().signOut();
throw error;
});
});
})
.catch((error) => {
console.log(error);
});
};

To catch an error from an async function, you can use try/catch and await the error:
const handleEmailSubmit = useCallback(async (e) => {
e.preventDefault();
const { email, password } = e.target.elements;
try {
await loginWithEmail(email.value, password.value);
history.push('/');
} catch(error) {
const message = await error.message;
setErrorMsg(message);
}
}, []);

You need to throw error in the catch statement.
app
.auth()
.signInWithEmailAndPassword(email, password)
.then((userCredential) => {
userCredential.user?.getIdToken(true).then((token: string) => {
axios
.get('https://dev.myserver.com/api/v1/users/auth', {
headers: { Authorization: `Bearer ${token}` },
})
.catch((error) => {
app.auth().signOut();
throw error;
});
});
})
.catch((error) => {
console.log(error);
throw error; // there could be something wrong here
});

Related

Here, I am getting trouble while i put data its not accessed by Firestore Database, plese tell where is the problem

I am getting error and its not responding what I expecting.
please tell where is problem.
while I tried to upload my data like name, email and expect to be uploaded to firebase database but it didn't it, and I got some error.
Please tell where is prob.
import React from 'react'
import Add from "../image/logo1.png"
import { createUserWithEmailAndPassword, updateProfile } from "firebase/auth";
import { auth , db, storage} from "../firebase";
import { useState } from 'react';
import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";
import { doc, setDoc } from "firebase/firestore";
const Register = () => {
const [err, setErr] = useState(false)
const handleSubmit = async (e) => {
e.preventDefault()
// console.log(e.target[0].value);
const displayName = e.target[0].value;
const email = e.target[1].value;
const password = e.target[2].value;
const file = e.target[3].files[0];
try {
const res = await createUserWithEmailAndPassword(auth, email, password);
const storageRef = ref(storage, displayName);
const uploadTask = uploadBytesResumable(storageRef, file);
uploadTask.on('state_changed',
(error) => {
setErr(true);
},
() => {`enter code here`
getDownloadURL(uploadTask.snapshot.ref).then(async(downloadURL) => {
await updateProfile(res.user,{
displayName,
photoURL:downloadURL,
})
await setDoc(doc(db, "users", res.user.uid),{
uid: res.user.uid,
displayName,
email,
photoURL: downloadURL,
});
});
}
);
} catch (err) {
setErr(true);
}
}
return (
<div className='formContainer'>
<div className='formWrapper'>
<span className="logo">Ut Chat</span>
<span className="title">Register</span>
<form onSubmit={handleSubmit}>
<input type="text" placeholder='display name' />
<input type="email" placeholder="email" />
<input type="password" placeholder="password" />
<input style={{ display: "none" }} type="file" id='file' />
<label htmlFor="file">
<img src={Add} alt="" />
<span>add an image</span>
</label>
<button>sign up</button>
{err && <span>something went wrong</span>}
</form>
<p>Do you have an account? Login</p>
</div>
</div>
)
}
export default Register
The first function in uploadTask.on() is an observer that triggers on upload progress but here you have error handle defined as first. Try refactoring the code as shown below:
uploadTask.on('state_changed',
(snap) => console.log("received update"),
(error) => {
setErr(true);
},
async () => {
`enter code here`
const fileUrl = await getDownloadURL(uploadTask.snapshot.ref)
await updateProfile(res.user, {
displayName,
photoURL: fileUrl,
})
await setDoc(doc(db, "users", res.user.uid), {
uid: res.user.uid,
displayName,
email,
photoURL: fileUrl,
});
});

How to call API when submitting the form?

I have the API and Login form, separately. Now I want to send my login credentials to API.
i don't know about how to call API and return data. const handleSubmit = (e) => {} inside of this, how to call API?
//login page
const initialFormData = Object.freeze({
username: "",
password: ""
});
export function LoginForm(props) {
const { switchToSignup } = useContext(AccountContext);
const [formData, updateFormData] = React.useState(initialFormData);
const handleChange = (e) => {
updateFormData({
...formData,
//whitespace
[e.target.name]: e.target.value.trim()
});
};
const handleSubmit = (e) => {
e.preventDefault()
console.log(formData);
this.props.history.push('/auth')
};
return (
<BoxContainer className="mobiview">
<FormContainer>
<Input type="text" placeholder="User name" name="username" onChange={handleChange}/>
<Input type="password" placeholder="Password" name="password" onChange={handleChange}/>
</FormContainer>
<SubmitButton type="submit" onClick={handleSubmit}>Signin</SubmitButton>
</BoxContainer>
//API (Its in another folder)
export const authProvider = {
// authentication
login: ({ username, password }) => {
const request = new Request(url + "/auth", {
method: "POST",
body: JSON.stringify({ username, password }),
headers: new Headers({ "Content-Type": "application/json" }),
});
...
...
}
}
Import the auth file, invoke from handleSubmit
import authProvider from "./path-to-file";
const handleSubmit = (e) => {
e.preventDefault()
console.log(formData);
const { username, password } = formData;
authProvider.login({
username,
password
});
};

.then promise not working within axios delete request in react application

I am trying to call a function to fetch data from the database upon deleting a note. This is so that the array of notes can be updated to reflect the deleted note. The function where the error occurs is called deleteNote and the function I am trying to call within the .then promise is getNotes.
Below is the code in my App.js file. If someone could help me solve this I'd greatly appreciate it.
import React, { useEffect, useState } from 'react';
import axios from 'axios';
// import HighlightOffIcon from '#material-ui/icons/HighlightOff';
import './App.css';
const App = () => {
const [note, setNote] = useState('');
const [notesList, setNotesList] = useState([]);
const getNotes = () => {
axios.get('http://localhost:8080/api')
.then((res) => setNotesList(res.data))
.catch(() => alert('Error recieving data.'));
}
useEffect(() => {
getNotes();
}, [])
const handleChange = (event) => {
const content = event.target.value;
setNote(content);
}
const handleSubmission = (event) => {
event.preventDefault();
axios({
url: 'http://localhost:8080/api/save',
method: 'POST',
data: {
content: note
}
})
.then((res) => {
console.log('Created Note');
setNote('');
getNotes();
})
.catch(() => {
console.log('Internal server error');
})
}
const deleteNote = (event) => {
const value = event.target.value;
axios({
method: 'DELETE',
url: 'http://localhost:8080/api/delete',
data: {
_id: value
}
})
.then(() => {
console.log('Note Deleted');
getNotes(); //Where the notes should be fetched upon successful deletion.
})
.catch(() => {
alert('Error deleting note.');
});
}
return (
<div className="app">
<h1>React Notes App</h1>
<form onSubmit={handleSubmission}>
<input
type="text"
placeholder="Enter note"
value={note}
onChange={handleChange}
/>
<button className="submit-button">Submit</button>
</form>
<div className="notes-list">
{notesList.map((note, index) => {
return (
<div className="note" key={index}>
<p>{note.content}</p>
<button value={note._id} className="delete-button" onClick={deleteNote}><i className="fas fa-trash-alt"></i></button>
</div>
);
})}
</div>
</div>
);
}
export default App;
I figured out the issue. When sending a request with axios, you must have a response sent back from the server in order to execute any code you may have in the promise.
example server code:
app.delete('/delete', (req, res) => {
BlogPost.delete({_id: req.body.id}, (err) => {
if (err) {
console.log(err);
} else {
console.log('Successfully deleted blog post.')
res.json({ //Must include a response to execute code within the axios promise.
msg: 'Delete request was recieved.'
});
}
});
});

Wait For The Result Of Dispatch (React-Redux)

Lets say I have a function that calls an api and get user data ,
export function submitLogin({email, password})
{
return (dispatch) =>
jwtService.signInWithEmailAndPassword(email, password)
.then((user) => {
debugger;
dispatch(setUserData(user));
return dispatch({
type: LOGIN_SUCCESS
});
}
)
.catch(error => {
debugger;
return dispatch({
type : LOGIN_ERROR,
payload: error
});
});
}
Now this is how I call this
function handleSubmit(model)
{
dispatch(authActions.submitLogin(model));
}
And Form
<Formsy
onValidSubmit={handleSubmit}
onValid={enableButton}
onInvalid={disableButton}
ref={formRef}
className="flex flex-col justify-center w-full"
>
Now please let me know how can I read the type sent by dispatch (as soon it receive response from an Api) inside submitLogin function also I would like to redirect to url if type is LOGIN_SUCCESS
const handleSubmit = async (model) => {
await dispatch(authActions.submitLogin(model));
}
export submitLogin = ({email, password}) => {
return async (dispatch) =>
await jwtService.signInWithEmailAndPassword(email, password)
.then((user) => {
debugger;
dispatch(setUserData(user));
return dispatch({
type: LOGIN_SUCCESS
});
}
)
.catch(error => {
debugger;
return dispatch({
type : LOGIN_ERROR,
payload: error
});
});
}
Try this way
function Example({ navigation }) {
const redirectCallback = () => {
// redirect here
navigation.navigate('Your Route');
}
function handleSubmit(model)
{
dispatch(authActions.submitLogin( model, () => redirectCallback() ) );
}
return(
<Formsy
onValidSubmit={handleSubmit}
onValid={enableButton}
onInvalid={disableButton}
ref={formRef}
className="flex flex-col justify-center w-full"
>
)
}
export function submitLogin({email, password}, callback)
{
return (dispatch) =>
jwtService.signInWithEmailAndPassword(email, password)
.then((user) => {
debugger;
dispatch(setUserData(user));
return dispatch({
type: LOGIN_SUCCESS,
callback: callback; // send callback here
});
}
)
.catch(error => {
debugger;
return dispatch({
type : LOGIN_ERROR,
payload: error
});
});
}
Create reducer and handle type LOGIN_SUCCESS
const reducer = (state = { isLoggedIn: false }, action) => {
switch (action.type) {
case LOGIN_SUCCESS:
action.callback(); call here
return state;
default:
return state;
}
};

Wait for promise to be resolved from React.Context, then render button

I have a function that fires when a user signs into the app.
signin: (email, password, setErrors, setUser, setUserIdToken) => {
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(res => {
const user = res.user
const isVerified = user.emailVerified
firebase
.auth()
.currentUser.getIdTokenResult()
.then(idTokenResult => {
setUserIdToken(idTokenResult)
})
.catch(error => console.log(error))
setUser(user)
const db = firebase.firestore()
if (isVerified) {
db.collection('/users')
.doc(user.uid)
.update({ isVerified: true })
}
})
.catch(err => {
setErrors(prev => [...prev, err.message])
})
},
I have another component that uses the user and userIdToken from the signIn method.
const Home = () => {
const { handleSignout, user, userIdToken } = useContext(firebaseAuth)
const { emailVerified, email } = user
const { claims } = userIdToken
return (
<div>
Home page component
<SurveyResults />
{emailVerified && email.endsWith('xxx') && !claims.admin ? (
<button type="button">hi</button>
) : null}
<button type="submit" onClick={handleSignout}>
sign out
</button>
</div>
)
}
export default Home
I don't have access to the properties of userIdToken immediatly when Home renders, as I am still waiting for the promise to resolve..But I also need to check the props of userIdToken to render a button. I'm not sure how to do that?

Categories

Resources