Handle promises inside redux actions with thunk - javascript

I have a fake login function like this
const login = (email, password) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (email === "demo#gmail.com" && password === "demo1234") {
resolve(200);
} else {
reject(401);
}
}, 1000);
});
};
This is my authAction.js file
export const login = (email,password) => async(dispatch) => {
try {
await fakeLogin(email,password)
dispatch({
type:LOGIN,
payload:{}
})
} catch (error) {
console.log(error)
}
}
In my LoginPage.js react component I call the action like this
const submit = ({ email, password }) => {
props.login(email, password).then((e) => console.log("then",e)).catch(err=>console.log("ca"));
};
If I pass the wrong credentials it logs the error code 401 inside the action. But in the LoginPage component, it always comes to the then block and prints undefined.
Even if I pass the right credentials it comes to then block and prints 'undefined'
But If I modify the action to return 200 or the error
export const login = (email,password) => async(dispatch) => {
try {
await fakeLogin(email,password)
dispatch({
type:LOGIN,
payload:{}
})
return 200
} catch (error) {
return error;
}
}
Now it prints the error code in "then" block of the LoginPage component.
Simply I want to inform the LoginPage component of what happened to the request. So what I am doing right now is okay or is there any other performance optimal way to do this?
Any help
Thanks in advance!

You forgot return value in then and throw error in catch
export const login = (email,password) => async(dispatch) => {
try {
const res = await fakeLogin(email,password)
dispatch({
type:LOGIN,
payload:{}
})
return res
} catch (error) {
console.log(error)
throw error
}
}

Related

React-native AsyncStorage Issue

In the code snippet you see, I am trying to reach the data that I have determined through asyncStorage in the getToken and `` functions, but when I open the page with these codes from the emulator, the data is empty for the first time, and then when I do ctrl+s from the editor, the data is full. What is the reason for this problem?
App.js Page
getToken: async () => {
const token = AsyncStorage.getItem('userToken');
return token;
},
getMail: async () => {
const mail = AsyncStorage.getItem('userMail');
return mail;
},
OrderListScreen Page
getToken().then((res) => {
if(res){
setToken(res);
console.log(token)
}else {
setToken('');
}
});
getMail().then((res) => {
if(res){
setMail(res);
console.log(mail)
}else {
setMail('');
}
});
Apply await before using AsyncStorage.getItem:
getToken: async () => {
const token = await AsyncStorage.getItem('userToken');
return token;
},
getMail: async () => {
const mail = await AsyncStorage.getItem('userMail');
return mail;
},
In the log you'll not get the updated state in next line of state setter.
getToken().then((res) => {
if(res){
setToken(res);
console.log(token); //You'll never get this value here because state updates are asynchronous in React
console.log("res : ", res);
}else {
setToken('');
}
});
getMail().then((res) => {
if(res){
setMail(res);
console.log(mail)//You'll never get this value here because state updates are asynchronous in React
console.log("Email Res : ", res);
}else {
setMail('');
}
});

How can I "encapsulate" this code into a module so it could become reusable?

I have got this Node.JS snippet and would like to write it as a module, so I can use recaptcha in different parts of my system.
This is how it currently looks like:
app.post('/register_user', (req, res) => {
const secret_key = process.env.RECAPTCHA_SECRET;
const token = req.body.recaptcha;
const url = `https://www.google.com/recaptcha/api/siteverify?secret=${secret_key}&response=${token}`;
fetch(url, { method: "post",})
.then((response) => response.json())
.then((google_response) => {
if (google_response.success == true) {
res.format({'text/html': () => res.redirect(303, '/register'),})
} else {
return res.send({ response: "Failed" });
}
})
.catch((error) => {
return res.json({ error });
});
})
I have tried to write the following module which works absolutely great, but I have absolute no idea about how to call it from the app.post, since I always get undefined as return:
import fetch from 'node-fetch';
export function fetch_out(url, timeout = 7000) {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('timeout')), timeout)
)
]);
}
export async function checkRecaptcha(token, secret_key){
const url = "https://www.google.com/recaptcha/api/siteverify?secret=" + secret_key + "&response=" + token;
try{
const response = await fetch_out(url, 1000);
const google_response = await response.json();
}catch(error){
return error;
}
return google_response;
}
Any help would be appreciated! Thanks!
You could make this method reusable by removing the framework actions that need to happen and only return if the validation was successful or not. This way, it will be reusable in another project that doesn't use a specific framework.
Example module;
export async function checkRecaptcha(token, secret_key) {
const url = `https://www.google.com/recaptcha/api/siteverify?secret=${secret_key}&response=${token}`;
const response = await fetch(url, { method: "post",});
if (!response.ok) return false;
const json = await response.json();
if (!json.success) return false;
return true;
}
Usage:
import { checkRecaptcha } from "./some-file-name";
app.post('/register_user', async (req, res) => {
const isHuman = await checkRecaptcha(req.body.recaptcha, process.env.RECAPTCHA_SECRET);
if (!isHuman) {
return res.send({ response: "Failed" });
}
return res.format({'text/html': () => res.redirect(303, '/register'),});
});
If you specifically want to call an action after the validation, you can also use successful and error callbacks.

memory leak error when redirect to home if user is not logged in

I've trying to redirect to home if user is not logged in(status 401) in componentDidMount.
So I tried
componentDidMount() {
const requestPatientListApi = async () => {
try {
const { data } = await get<AxiosResponse<PatientApi>>("/patient", { requester: "admin" });
return data.items;
} catch (err) {
//when user is not logged in redirect to "./"
props.history.push("./");
}
return [];
};
if (!axios.isCancel("")) {
// updating state when api call is not canceled
requestPatientListApi().then(patients => {
setPatients(patients);
});
}
}
componentWillUnmount() {
if (cancel) {
cancel();
}
}
But, the error occurs:
Warning: Can't perform a React state update on an unmounted component.
I've tried using axios cancel token, but it seems not a solution for this case.
Any ideas?
The issue is that you're redirecting before setting a state, in which case the component is not rendered anymore. One way would be to forward the error in your async func and catch it later.
componentDidMount() {
const requestPatientListApi = async () => {
try {
const { data } = await get <AxiosResponse<PatientApi>>("/patient", {
requester: "admin"
});
return data.items;
} catch (err) {
throw err; // Forward the error further
}
return [];
};
if (!axios.isCancel("")) {
requestPatientListApi().then(patients => {
setPatients(patients);
}).catch(err => {
props.history.push("/"); // handle the error here
});
}
}

catch not running javascript

I have an async await function that handles form submission in React Native:
const handleSubmit = async () => {
const credentials = { email, password }
try {
login(credentials)
} catch {
console.error('ERROR')
//external function to reset form
resetForm()
return
}
// User authenticated, go to home screen
await goToHomeScreen()
}
Where login(), which makes the API call, is
const login = (credentials) => {
axios
.post(`${MY_API}/login`, credentials)
.then((res) => {
console.log(res.data)
})
.catch(() => {
throw 'Error'
})
}
The idea is that if the authentication call fails, my login() throws an error, which should run the return in my handleSubmit's catch {}, ending the function. However, the catch never runs, and goToHomeScreen() runs. What am I doing wrong?
not just return but do something
axios
.get(url)
.then((response) => {
console.log('response', response);
}
.catch((error) => {
console.log('CATCH');
window.alert('CATCH');
}
Try this, it is working for me
const login = (credentials) => {
axios
.post(`${MY_API}/login`, credentials)
.then((res) => {
console.log(res.data)
})
.catch((error ) => {
return Promise.reject(error);
})
}
since you are using async-await, you can call login as:
const handleSubmit = async () => {
const credentials = { email, password }
try {
await login(credentials)
} catch {
console.error('ERROR')
//external function to reset form
resetForm()
return
}
// User authenticated, go to home screen
await goToHomeScreen()
}
const login = async (credentials) => {
return await axios.post(`${MY_API}/login`, credentials);
}
it will solve the issue

react.js: Create resource with redux-form, rest api and async/await

I'm trying to create new resource with redux form and REST api.
I dispatch createPost action and I want to check if the post was succeeded before continue.
const handleFormSubmit = (values, dispatch) => {
dispatch(createPost(values));
//I want to check here if post was succeeded.
//if status = 200 this.props.history.push('/');
}
export function createPost(values) {
return async function(dispatch) {
let request;
try {
request = await axios.post(`${ROOT_URL}/posts`, values)
} catch(err) {
request = { err };
}
dispatch({
type: CREATE_POST,
payload: request
})
}
}
Return a promise, something like this :
export function createPost(values) {
return function(dispatch) {
return new Promise( async function(resolve, reject){
let request;
try {
request = await axios.post(`${ROOT_URL}/posts`, values)
} catch(err) {
reject(err)
}
dispatch({
type: CREATE_POST,
payload: request
})
resolve(request)
})
}
}
const handleFormSubmit = () => {
dispatch(createPost(values))
.then( res => {
// do yoour stuff on succes
} )
.catch(err => {
// stuff on err
})
}
As seeing your codes, I don't think you need to use promise.
Please try like following:
const getAction = (values) => (dispatch) => {
return axios
.post(`${ROOT_URL}/posts`, values)
.then(
() => {
dispatch({
type: CREATE_POST,
payload: request
})
},
() => {
throw new SubmissionError({
_error: 'Failed'
});
}
);
};
const handleSubmit = (values) => {
return dispatch(getAction(values));
};

Categories