How do I handle errors in a redux action? - javascript

import axios from "axios";
export const createNewUser = (newUser, history) => async dispatch => {
try {
await axios.post("http://localhost:9090/users/register", newUser);
history.push("/login");
dispatch({
type: "GET_ERRORS",
payload: {}
});
} catch (err) {
dispatch({
type: "GET_ERRORS",
payload: err.response.data
});
}
};
This is my action,I have a form where I bind the inputs to my state and I'm calling the action when I submit the form as such:
onSubmit(e) {
e.preventDefault();
const newUser = {
"username": this.state.username,
"fullName": this.state.fullName,
"password": this.state.password,
"confirmPassword": this.state.confirmPassword
};
console.log(this.props)
this.props.createNewUser(newUser, this.props.history);
}
componentWillReceiveProps(nextProps) {
console.log(nextProps)
if (nextProps.errors) {
this.setState({ errors: nextProps.errors });
}
}
This is all covered in a tutorial for spring boot and react, I believe that I followed it exactly however I am not getting the same results. I even copied the code as it is in the tutorial. When I click submit I see a 400 error in the console, but the state ( errors) stays undefined.
This is what my backend returns when I checked with debugger:
<400 BAD_REQUEST Bad Request,{password=Password must be atleast 6 characters, fullName=Please enter your full name, username=username is required},[]>

Related

Async function in another file is not being hit

Currently, I'm trying to create a login and for some reason my code for my login is not being triggered. The function loginUserWithEmail is not being triggered.
It is not being triggered because none of the console.log's inside the loginUserWithEmail function is printed in the console.
The onSubmit() function in Login.tsx is triggers when I click a "Login" button.
Thank you.
Login.tsx:
import { useFormik } from 'formik';
import { loginUserWithEmail, LoginFormData } from '../../actions/authActions'
const Login = ({ auth, history, login }: {auth: any, history: RouteComponentProps['history'], login: any}) => {
const formik = useFormik({
initialValues: {
email: '',
password: '',
},
validationSchema: loginSchema,
onSubmit: (values: LoginFormData) => {
console.log("before loginuserwithemail");
loginUserWithEmail(values, history);
console.log("after")
},
});
...
}
authActions.ts
export const loginUserWithEmail = (formData: LoginFormData, history: RouteComponentProps['history']) => async (dispatch: any, getState: any) => {
console.log("inside loginuserwithemail function")
dispatch({ type: LOGIN_WITH_EMAIL_LOADING });
try {
const response = await axios.post('/auth/login', formData);
console.log("inside here")
dispatch({
type: LOGIN_WITH_EMAIL_SUCCESS,
payload: { token: response.data.token, me: response.data.me },
});
dispatch(loadMe());
history.push('/');
} catch (err: any) {
dispatch({
type: LOGIN_WITH_EMAIL_FAIL,
payload: { error: err.response.data.message },
});
}
};
loginUserWithEmail is hoc (function that returns function)
You need it to call function returned by this function
await loginUserWithEmail(values, history)(dispatch, getState);

Dispatching with react-redux

I'm trying to call a function from React JSX button and I have a problem with that because when in react-redux actions in the defined function I don't put dispatch function, works as it supposed to.
const like_function = (id) => {
let post_id = id;
if (isAuthenticated) {
console.log(post_id, user_id);
like_post(post_id, user_id);
} else {
<Redirect to="/login" />;
console.log("Redirect to login");
}
};
Here in this button I invoke function with one parameter.
<button onClick={() => like_function(post.id)}>Like</button>
This is redux action. Here is the problem. When dispatch is deleted function works but with dispatch is not even called, it wont even log data to console before async request
export const like_post = (post_id, user_id) => async (dispatch) => {
const data = { post_id: post_id, user_id: user_id };
console.log(data);
dispatch({
type: POST_LIKE_LOADING,
});
try {
const res = await axios.put(`http://localhost:8000/api/like_list/`, data);
//console.log(res.data);
dispatch({
type: POST_LIKED,
payload: res.data,
});
} catch (err) {
console.log(err);
dispatch({
type: POST_LIKEING_FAIL,
});
}
};
Here are my redux reducers
case POST_LIKE_LOADING:
return {
...state,
isLoading: true,
};
case POST_LIKED:
return {
...state,
isLoading: true,
message: "OK"
};
Sorry about my English, hope you understood me, thanks in advance
You're not dispatching the action.
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
dispatch(like_post(post_id, user_id))

TypeError: Cannot read property 'type' of undefined in react js

I am using jumbo 4.1.1 template. I get the response, but this error occurs.
My code is below:
authAction.js:
...
export const userSignIn = (user) => {
// const {email, password} = user;
console.log(user)
axios.post(base_url +'login', user)
.then(response=> {
console.log(response.data)
return {
type: SIGNIN_USER,
payload: user
};
})
};
But when I run the project, I got the error TypeError: Cannot read property 'type' of undefined
I believe that is because you have not dispatched the action properly.
Are you using thunk?
If you are using Redux and making an async call, you should return dispatch.
const userSignup = (signupData) => {
return async (dispatch) => {
try {
let res = await axios.post(`${url}/user/`, { user: signupData });
dispatch({
type: "FETCH_CURRENT_USER_SUCCESS",
payload: res.data.user,
});
return true;
} catch (error) {
console.log(
"%c CATCH in userSignup ",
"background: red; color: #bada55",
error
);
}
};
};
Notice, that I am returning a function with dispatch as an argument in the second line. and then using that dispatch (4th line) that dispatches the action's type and payload.
Also I'm returning something from the function userSignUp, finally, so the invoker of the function userSignUp gets something in response.
If you don't understand anything above, please do let me know.
You could benefit from using async + await here.
For example:
export const userSignIn = async (user) => {
try {
// const {email, password} = user;
console.log(user);
const data = await axios.post(base_url +'login', user);
console.log(data);
return {
type: SIGNIN_USER,
payload: user,
};
} catch (error) {
console.log(error);
// return an error action...?
return {
type: ERROR,
payload: error,
};
}
};

Why isn't my dispatch working? React Redux

I´m trying to change my firebase username using the redux store.
I have a register form that receive the email, password and username of the input and then the form create a firebase account with email and password, then I update the displayName using updateProfile of firebase. See this
That´s my redux reducer:
case "CHANGE_USERNAME":
const currentUser = firebase.auth().currentUser;
currentUser.updateProfile({ displayName: state.user.displayName });
return { ...state.user, displayName: action.payload };
This is the store:
const initialState = {
logged: null,
user: {}
};
And this is part of my register form:
firebase
.auth()
.createUserWithEmailAndPassword(this.state.email, this.state.password)
.then(() => {
this.props.dispatch({
type: "CHANGE_USERNAME",
payload: { ...this.state.username }
});
alert("Account created!");
})
.catch(error => {
// Handling errors
var errorCode = error.code;
var errorMessage = error.message;
alert(errorCode);
});
Why the username is not changing?
You aren't returning anything from your promise. Assuming that createUserWithEmailAndPassword returns a promise, and that the response contains a username field, you want to dispatch response.username to your reducer.
.then((response) => {
this.props.dispatch({
type: "CHANGE_USERNAME",
payload: { response.username }
});
alert("Account created!");
})
In your reducer, you want to add the new username state. Something like:
return { ...this.state, username: payload }
Thanks all, I had fixed the problem using:
case "CHANGE_USERNAME": {
const currentUser = firebase.auth().currentUser;
currentUser.updateProfile({ displayName: action.payload });
return {
...state,
user: { ...currentUser.providerData[0] }
};
}
At my reducer and:
this.props.dispatch({
type: "CHANGE_USERNAME",
payload: this.state.displayName
});
At my dispatch, thanks!

Waiting for state to change in react with redux

i am using redux in react-native to fetch data from an api, here is whhat i have done so far
api_type.js
export const USER_LOGIN = 'user_login_action';
export const USER_LOGINING = 'logining_users';
export const USER_LOGEDIN = 'user_logged_in';
index.js
import axios from 'axios';
import { USER_LOGIN, USER_WALLETS,USER_LOGINING } from './api_types';
const AUTH_API_URL = 'http:/api/v1';
const CORE_API_URL = 'http:/api/v1';
let username="";
let password="";
let auth_token ="";
let AuthStr = "";
export function UserWallets(){
return function(dispatch){
AuthStr ="Bearer "+auth_token;
console.log ("new auth : "+AuthStr);
axios.defaults.headers.common['Authorization'] = AuthStr
axios.get(`${CORE_API_URL}/wallet/allwallets`)
.then(response => {
dispatch({
type: USER_WALLETS,
payload: response['data']
});
}).catch((error) => {
console.log(error);
})
}
}
export function UserLogin() {
return function(dispatch) {
dispatch({
type:USER_LOGINING
});
axios.post(
`${AUTH_API_URL}/authenticate/users`,
{
email: username,
password: password
}
)
.then(response => {
dispatch({
type: USER_LOGIN,
payload: response['data']
});
auth_token=response['data']['token'];
}
)
.catch((error) => {
console.log(error);
})
}
}
export function username(term) {
username=term;
console.log("username " +username);
return{
type:"username",
username
};
}
export function password(term) {
password=term;
console.log("password " +password);
return{
type:"password",
password
};
}
export function authToken (term){
auth_token = term;
return{
type:"authtoken",
auth_token
}
}
auth_reducer.js
import { USER_LOGIN ,USER_LOGINING } from '../actions/api_types';
const INTIAL_STATE = {
message: '',
token:'',
logging: false,
loggedin: false,
loginerr: null,
};
export default function (state = INTIAL_STATE, action) {
console.log("present state"+action.type);
switch(action.type) {
case USER_LOGIN:{
return { ...state, message: action.payload.message, token:action.payload.token,loggedin:true};
}
case USER_LOGINING:{
return {...state,logging:true }
}
default:{
console.log("default "+action.type);
}
}
return state;
}
index.js // combine reducer
import { combineReducers } from 'redux';
import drawer from './drawer';
import AuthReducer from './auth_reducer';
import CoreReducer from './core_reducer';
export default combineReducers({
auth: AuthReducer,
});
i have created and configured the store and wrapped my app with the provider from react-redux, and i have passed the store to the provider, in a nutshell i can now access the store from my componets.
below is a function in my login_component, that triggers once i click on login
login(){
if(this.state.email==""){
alert("Email require");
return;
}else if(this.state.password==""){
alert("password require");
return;
}else{
//set the paramter for the reducer to use
this.props.username(this.state.email);
this.props.password(this.state.password);
//activate the user login action
this.props.UserLogin();
if(!this.props.auth.loggedin){
console.log("logging in");
//show loadging gif
}
//checking from response from the auth api
if(this.props.auth.message=="user successfully logged in"){
alert(this.props.auth.token);
Actions.home();
}else{
alert("invalid Username/Password");
}
}
}
Now this is problem, once i click on login, the block of code i commented (check response from api) will not wait for the store value to change before it perform it action, please i need a way around this.
i finally got a solution to the problem, the api call was async but the problem was that in the component, i tested for the response before the store changes so here is the solution, i added the following to my login component
componentWillReceiveProps(nextProps) {
console.log("component update");
if(nextProps.auth.loggedin==true){
if(nextProps.auth.message=="user successfully logged in"){
this.setState(previousState => {
return { spinnerv: false };
});
Actions.home();
}else{
alert("invalid Username/Password");
}
}
}
what happens here is that function componentWillReceiveProps, check if the states has changed and then text if the response is componentWillReceiveProps.
thanks jmargolisvt for your support.
i hope this help someone else.
You need to perform this API call asynchronously. Basically, you will have your login function dispatch an async action that will make the API call. Then from your success/fail methods of the API call, you'll dispatch another (synchronous) call that either logs the user in or not.
You'll want to incorporate Redux Thunks to make your async call.
https://github.com/gaearon/redux-thunk

Categories

Resources