Behaviour of dispatch function on catch block - javascript

I was building a login system on my app and I found a weird behaviour of the dispatch function.
I'm using React with Redux, Redux-Thunk and Redux-Form.
On my actions/index.js file, after making an axios request, the dispatch function, when I'm using the .then().catch() syntax works perfectly but when I change to async/await syntax the second dispatch doesn't work any more. I try to find explanation online but I didn't found any that clarified my problem. Does someone know why does that happens?
Version that works perfectly:
export const submitLoginForm = values => dispatch => {
axios.post(
'/auth/local/login',
qs.stringify({
email: values.email,
password: values.password
})
)
.then(res => {
dispatch({ type: FETCH_USER, payload: res.data });
})
.catch(err => {
dispatch(
stopSubmit('enterpriseLogin', {
_error: 'Error description...'
})
);
});
}
Version that second dispatch doesn't work:
export const submitLoginForm = values => async dispatch => {
try {
const res = await axios.post(
'/auth/local/login',
qs.stringify({
email: values.email,
password: values.password
})
);
dispatch({ type: FETCH_USER, payload: res.data });
} catch (err) {
//Doesnt Work !!
dispatch(
stopSubmit('enterpriseLogin', {
_error: 'Error description...'
})
);
}
}

Related

trycatch block not sent error when error triggers

iam using react-redux here and when i use trycatch block it not triggers error when error is executed.why??
import {
LOGIN_REQUEST,
LOGIN_SUCCESS,
LOGIN_FAIL,
CLEAR_ERRORS,
} from "../constants/userConstant";
impo
rt axios from "axios";
export const login = (email, password) => async (dispatch) => {
try {
dispatch({ type: LOGIN_REQUEST });
const config = { headers: { "Content-Type": "application/json" } };
const { data } = await axios.post(
`/api/v1/login`,
{ email, password },
config
);
dispatch({ type: LOGIN_SUCCESS, payload: data.user });
} catch (error) {
dispatch({ type: LOGIN_FAIL, payload: error.response.data.message });
}
};
//Clearing errors
export const clearErrors = () => async (dispatch) => {
dispatch({ type: CLEAR_ERRORS });
};
=>It was showing LOGIN_FAIL in react-redux-devtools but it was not throwing an error
catch (error) {
dispatch({ type: LOGIN_FAIL, payload: error.response.data.message });
// Log your error in the console
console.log(error);
// throw error
throw error
}
If you want to console error or throw error do it this way but you actually just call your dispatch for the moment.
The try catch blocks are here to handle every situations your function meet, when an error come it's been caught but YOU have to decide how to handle this error.

my redux toolkit state is not updating properly

My redux toolkit dispatch is firing twice, once immediately which for some reason doesn't properly update the state, then my entire app breaks because it cant't find the info that us supposed to have been provided, then it fires again and updates properly. So if i refresh the page then everything will load up because then it gets the information from my persistent storage in time.
This is the portion of the code where the dispatch is called:
const handleSignUp = (e) => {
e.preventDefault();
createUserWithEmailAndPassword(auth, email, password)
.then((cred) => {
updateProfile(cred.user, { displayName: name })
.then(() => {
dispatch(
login({
name: name,
uid: cred.user.uid,
jobDesc: jobDesc,
email: email,
})
);
})
})
.catch((err) => {
console.log(err);
})
.finally(() => {
setPassword("");
});
};
This is the userSlice where login is called from:
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
user: null,
};
export const userSlice = createSlice({
name: "user",
initialState,
reducers: {
login: (state, action) => {
state.user = action.payload;
},
logout: (state) => {
state.user = null;
},
},
});
export const { login, logout } = userSlice.actions;
export default userSlice.reducer;
i have checked my redux dev tools so i know the dispatch calls twice and if first udpates partially and the completely.
this is text copied from my dev tools console that displays the state and it's changes:
name(pin):null
uid(pin):"CK3uLpCLD3hIOa0vXEzhA0oFcwr1"
email(pin):"jamesdev#gmail.com"
that is the first update and this is the second:
name(pin):"james"
uid(pin):"CK3uLpCLD3hIOa0vXEzhA0oFcwr1"
jobDesc(pin):"web dev"
email(pin):"jamesdev#gmail.com"
I've almost lost my mind trying to figure this out, please help.
Edit:
Sometimes it also throws this error at Login:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
You are missing a return there at one place, which leads to the whole thing not waiting, but running in parallel:
.then((cred) => {
// vvv this was missing
return updateProfile(cred.user, { displayName: name })
.then(() => {
dispatch(
login({
name: name,
uid: cred.user.uid,
jobDesc: jobDesc,
email: email,
})
);
})
})
Generally I'd highly recommend writing the whole thing as async function with await instead as that makes it a whole lot more readable:
const handleSignUp = async (e) => {
e.preventDefault();
try {
const cred = await createUserWithEmailAndPassword(auth, email, password)
await updateProfile(cred.user, { displayName: name })
dispatch(
login({
name: name,
uid: cred.user.uid,
jobDesc: jobDesc,
email: email,
})
);
} catch (err) {
console.log(err);
} finally {
setPassword("");
};
};

Redux dispatch never run in React Native app

I have an authentication action on an react native app which must during the authentication go to perform another action but it is never executed (dispatch(getMobiles())). I do not understand why. Do you have an idea ?
If my authentication went well, I immediately want to retrieve data on my new users, so I want to execute getMobiles () which is another action.
thanks in advance :)
auth actions
export const authentication = (
username: String,
password: String,
label: String,
synchro: Boolean,
url: String,
) => {
return dispatch => {
dispatch({type: LOGIN.PENDING, payload: ''});
const type = UDA_URL_LIST.map(uda => {
if (uda.url === url) {
return uda.name;
}
})
.join()
.replace(/[, ]+/g, ' ')
.trim();
fetchUser(url, username.trim(), password.trim())
.then(response => {
if (!response.err) {
const newUser = {
...response,
label,
type,
synchro,
};
dispatch({type: LOGIN.SUCCESS, payload: newUser});
// not dispatched !
return dispatch(getMobiles(url, response.key, newUser.userId));
}
})
.catch(err => dispatch({type: LOGIN.ERROR, payload: err}));
};
};
getMobiles
export const getMobiles = (
url: String | null = null,
token: String,
userId: String,
) => {
return dispatch => {
dispatch({type: MOBILES.PENDING, payload: ''});
fetchMobiles(url, token)
.then(mobilesList => {
dispatch({
type: MOBILES.SUCCESS,
payload: mobilesList.data,
meta: {userId},
});
})
.catch(err => alert(err));
};
};
};
Your code in getMobiles require second call with parametr dispatch,
try to use getMobiles(url, response.key, newUser.userId)(dispatch)

How to adjust the order of events occurring in async Javascript?

I am working on authentication for my react native app.
The problem I am having is that the signInUser function seems to be executing in the wrong order. I want the signIn function to fully execute before moving on.
However, that doesn't seem to be happening as I am getting this response in my console, with the "undefined" coming from console.log(response) in the SignInScreen.
Here is the console:
undefined
16d0707a3508a9b43b8c36c8574ca73d8b4b26af
I have this function in the SignInScreen.js
import { signIn } from "../services/authService";
import { useAuthDispatch } from "../contexts/authContext";
const SignInScreen = ({ navigation }) => {
const dispatch = useAuthDispatch();
const [signInLoading, setSignInLoading] = useState(false);
const signInUser = async (values) => {
const { email, password } = values;
setSignInLoading(true);
signIn(email, password)
.then((response) => {
console.log(response);
dispatch({
type: "SIGN_IN",
token: response,
});
})
.catch((e) => {
console.log(e);
})
.finally(() => setSignInLoading(false));
};
And this is my authService.js:
import axios from "axios";
const signIn = async (email, password) => {
axios
.post("http://127.0.0.1:8000/rest-auth/login/", {
username: email,
email: email,
password: password,
})
.then((response) => {
console.log(response.data.key);
return response.data.key;
})
.catch((error) => {
return error;
});
};
How can I fix this?

ReactJS: How to implement react-cookie properly in an action?

I have read articles that saving the token in localstorage is dangerous to XSS attack. So I have decided to store my tokens in cookies. And I am using react-cookie. I saw the examples and I am trying to do it but my auth.js consists of const and is not a class, so I do not know how to use the withCookies() with it, this is my auth.js where I want to store the token to the cookies:
import {
LOGIN,
LOGIN_SUCCESS,
LOGIN_FAILED,
GET_USER_DATA,
GET_USER_DATA_SUCCESS,
GET_USER_DATA_FAILED,
LOGOUT,
LOGOUT_SUCCESS,
LOGOUT_FAILED,
} from './types'
import axios from 'axios'
var api = require ('./../api.js');
export const login = (email, pass) => {
return (dispatch) => {
dispatch({
type: LOGIN
})
var url = api.logInApi
axios.post(url, {
email: email,
password: pass
})
.then(res => {
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
})
localStorage.setItem('token', res.data.token)
dispatch(getUserData())
})
.catch(err => dispatch({
type: LOGIN_FAILED,
payload: err
}))
}
}
export const getUserData = () => {
return (dispatch) => {
dispatch({
type: GET_USER_DATA
})
var url = api.getUserDataApi
axios.post(url, {}, {headers: {
"Authorization": `Bearer ${localStorage.getItem("token")}`
}})
.then(res => {
dispatch({
type: GET_USER_DATA_SUCCESS,
payload: res.data
})
})
.catch(err => dispatch({
type: GET_USER_DATA_FAILED,
payload: err
}))
}
}
export const logout = () => {
return (dispatch) => {
dispatch({
type: LOGOUT
})
var url = api.logoutApi
axios.post(url, {}, {headers: {
"Authorization": `Bearer ${localStorage.getItem("token")}`
}})
.then(res => {
window.location.replace("")
dispatch({
type: LOGOUT_SUCCESS,
payload: res.data
})
})
.catch(err => dispatch({
type: LOGOUT_FAILED,
payload: err
}))
}
}
Now, I tried doing this and of course it doesn't work:
import {
LOGIN,
LOGIN_SUCCESS,
LOGIN_FAILED,
GET_USER_DATA,
GET_USER_DATA_SUCCESS,
GET_USER_DATA_FAILED,
LOGOUT,
LOGOUT_SUCCESS,
LOGOUT_FAILED,
} from './types'
import axios from 'axios'
import { withCookies, Cookies } from 'react-cookie'; <<added this
var api = require ('./../api.js');
const login = (email, pass) => {
return (dispatch) => {
dispatch({
type: LOGIN
})
const { cookies } = props; <<added this
var url = api.logInApi
axios.post(url, {
email: email,
password: pass
})
.then(res => {
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
})
cookies.set('token', res.data.token, { path: '/' }); <<added this
dispatch(getUserData())
})
.catch(err => dispatch({
type: LOGIN_FAILED,
payload: err
}))
}
}
export default withCookies(login) <<added this(wrong)
const getUserData = () => {
return (dispatch) => {
dispatch({
type: GET_USER_DATA
})
const { cookies } = props; <<added this
var token = cookies.get('token'); <<added this
var url = api.getUserDataApi
axios.post(url, {}, {headers: {
"Authorization": `Bearer ${token}` <<added this(this is where I wanna get the cookie)
}})
.then(res => {
dispatch({
type: GET_USER_DATA_SUCCESS,
payload: res.data
})
})
.catch(err => dispatch({
type: GET_USER_DATA_FAILED,
payload: err
}))
}
}
export default withCookies(getUserData) <<added this(wrong)
const logout = () => {
return (dispatch) => {
dispatch({
type: LOGOUT
})
const { cookies } = props;
var token = cookies.get('token');
var url = api.logoutApi
axios.post(url, {}, {headers: {
"Authorization": `Bearer ${token}` <<added this
}})
.then(res => {
window.location.replace("")
dispatch({
type: LOGOUT_SUCCESS,
payload: res.data
})
})
.catch(err => dispatch({
type: LOGOUT_FAILED,
payload: err
}))
}
}
export default withCookies(logout) <<added this(wrong)
this one is wrong because there should only be one export default. But I don't know how to implement withCookies to const and there are also these ones that are included in the example and I don't know if I need them or where do I put them:
static propTypes = {
cookies: instanceOf(Cookies).isRequired
};
constructor(props) {
super(props);
const { cookies } = props;
this.state = {
name: cookies.get('name') || 'Ben'
};
}
and also, another question is that, I can access my cookies anywhere in my project right? just like how localstorage is accessible to my project?
I hope someone can help me and I am a newbie to this. I have never used cookies before so thank you for your consideration.
I personally would rather using js-cookie to write/read cookies.
It has a very basic API:
Cookie.set('cookie_name', 'value') // will set "cookie_name" to "value"
Cookie.get('cookie_name') // will return "value"
Which means:
const login = (email, pass, cookie) => {
return (dispatch) => {
dispatch({
type: LOGIN
})
var url = api.logInApi
axios.post(url, {
email: email,
password: pass
})
.then(res => {
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
})
cookies.set('token', res.data.token);
dispatch(getUserData())
})
.catch(err => dispatch({
type: LOGIN_FAILED,
payload: err
}))
}
}
Passing to the login funuction js-cookie's Cookie in the 3rd argument.
Now, you can still use the same react-cookie package to read the cookie values (I believe there shouldn't be any conflicts). Or you can replace it with js-cookie. To do that, however, you will have to pass the Cookie object to props. I probably would do that using mapStateToProps if you're using Redux or just by simply passing it through JSX

Categories