Redux dispatch never run in React Native app - javascript

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)

Related

What type should be used with async dispatch?

I am creating a project with TypeScript using React.
In an action file which is loginAction.tsx, I have a line like this:
export const login = (obj) => async dispatch => {
dispatch({
type: LOGIN_REQUEST,
});
const response = await axios.post(`/api/login`, obj);
if (response.data && response.data.status === 'success') {
dispatch({
type: LOGIN_SUCCESS,
payload: response.data
});
} else if (response.data && response.data.status === 'failure') {
dispatch({
type: LOGIN_FAILURE,
payload: response.data
});
}
}
This works fine in JavaScript. But in TypeScript, I am not sure what return types I should use and how I can use them. I have tried in some ways but none of them are getting accepted. Every time I am getting an error in the line "export const login = (obj) => async dispatch =>". Can anyone help me to write this portion correctly in TypeScript?
PS: I tried to use the first line like this:
interface ILoginObject {
email: string,
password: string
}
export const login = (loginObject: ILoginObject) => async dispatch => {}
But it says, "Missing return type on function" and shows the error by underlining the "async dispatch =>" portion.
interface ILoginObject {
email: string,
password: string
}
interface ILoginDispatch {
type: string,
payload?: {
success? : boolean,
status?: number,
message?: string,
user?: {
id: string,
email: string
},
access_token?: string,
expires_in?: string
}
}
export const userLogin = (loginObject: ILoginObject) => async (dispatch: Dispatch<ILoginDispatch>): Promise<void> => {
dispatch({
type: LOGIN_REQUEST
});
const response = await axios.post(`/api/login`, loginObject);
if(response.data && response.data.access_token) {
dispatch({
type: LOGIN_SUCCESS,
payload: response.data
});
}
else {
dispatch({
type: LOGIN_FAILURE,
payload: response.data
});
}
}

When a function inside my actions is called it won't work unless I take out the dispatch

I'm working with React Redux, and I'm trying to call a function inside another function on my actions file. The problem is It only work if I take the dispatch part of the function.
I wan't to call updateToken() from askForUser() but it will only work if I take the dispatch part from updateToken(). Also when i call askForUser() from askForUser() it won't work either.
const updateToken = (token) => dispatch => {
console.log(token)
dispatch({
type: UPDATE_TOKEN,
payload: token
})
}
const askForUser = (token) => dispatch => {
dispatch({ type: ASKING_FOR_DATA })
axios.get(API.GET_USER, {
params: {
token
}
}).then((response) => {
if (response.data.status === 1) {
dispatch({ type: ASK_FOR_USER, payload: response.data.user })
} else if (response.data.status === 2) {
updateToken(response.data.token)
//console.log(hola2())
} else {
NotificationManager.error('Error consiguiendo usuario')
dispatch({ type: ERROR_HANDLER })
}
}).catch((err) => {
console.log(err)
dispatch({ type: ERROR_HANDLER })
})
}
you'll have to dispatch it :
else if (response.data.status === 2) {
dispatch(updateToken(response.data.token)); // dispatch the function here
}

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

Behaviour of dispatch function on catch block

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...'
})
);
}
}

NGRX state property disappears

I'm trying to get user info from database. In component I'm getting decoded id from service, then call the action which takes the id as parameter. It returns the user, there is response in network tab. The state property 'currentUser' is null all the time until it should change to response, then it disappears.
export interface State {
loading: boolean;
loggedIn: boolean;
currentUser: User;
}
const initialState: State = {
loading: false,
currentUser: null,
loggedIn: localStorage.getItem("token") ? true : false
};
case AuthActions.GET_USER_SUCCESS:
{
return {
...state,
loading: false,
loggedIn: true,
currentUser: action.user
};
}
#Effect()
getUserInfo$: Observable < Action > = this.actions$
.ofType(fromActions.GET_USER)
.pipe(map((action: fromActions.GetUser) => action.id),
concatMap(id => {
return this.authService.getUser(id);
})
)
.pipe(map((res: User) => ({
type: fromActions.GET_USER_SUCCESS,
payload: res
})));
}
Try it like this:
#Effect()
getUserInfo$: Observable<Action> = this.actions$
.ofType(fromActions.GET_USER)
.pipe(
map((action: fromActions.GetUser) => action.id),
concatMap(id =>
this.authService.getUser(id).pipe(
map((res: User) => ({
type: fromActions.GET_USER_SUCCESS,
payload: res
}))
)
)
);
What is the shape of your action class? I can see you dispatch an action in the shape of
{
type: fromActions.GET_USER_SUCCESS,
payload: res
}
but in your reducer you expect it to have a user property on it
case AuthActions.GET_USER_SUCCESS:
{
return {
...state,
loading: false,
loggedIn: true,
currentUser: action.user // <- try action.payload or action.payload.user,
// depending on what you get from the API
};
}
Also, try to shape your effect more like this:
#Effect()
getUserInfo$: Observable <Action> = this.actions$
.ofType(fromActions.GET_USER)
.pipe(
switchMap(({ id }) => this.authService.getUser(id)
.pipe(
map((res: User) => ({ type: fromActions.GET_USER_SUCCESS, payload: res }),
// Handling errors in an inner Observable will not terminate your Effect observable
// when there actually is an error
catchError(err => ({ type: fromActions.GET_USER_ERROR, payload: err })
)
)
);
Hope this helps a little :)

Categories