I call a state function in my component, the function should change the state(and it does but late), i want to log the change but the log triggers before the state is changed
this is the function in the state:
const login = async (user, password) => {
const body = {
username: user,
password: password,
};
await axios
.post('/sessions', body, {
headers: { 'Content-Type': 'application/json' },
})
.then((resp) => {
dispatch({ type: LOGIN, payload: resp.data.data });
})
.catch((err) => {
console.log(err.response.data);
});
};
and this is the call in the component
const onSubmit = (e) => {
e.preventDefault();
login(user, password);
console.log(credes);
};
"credes" is the state for that response, but it keeps printing the initial state witch is an empty object
the function triggers on the form submission but logs first and updates the state later.
As pointed out by bubulledu93, ronakvp and coreyward, I was butchering the syntax. I was trying to perform two actions in one function, so I moved the log into a useEffect to watch for changes in the "credes" hope is the right way but is working as I needed it.
const login = (user, password) => {
const body = {
username: user,
password: password,
};
axios
.post('/sessions', body, {
headers: { 'Content-Type': 'application/json' },
})
.then((resp) => {
dispatch({ type: LOGIN, payload: resp.data });
})
.catch((err) => {
console.log(err.response.data);
});
};
and the call in the component + the useEffect
const onSubmit = (e) => {
e.preventDefault();
login(user, password);
};
useEffect(() => {
if (credes.success) {
console.log(credes.data);
}
}, [credes]);
There isn't any benefit to awaiting as the last call in a function. Instead of using async and await, simply return the Promise chain started by axios.post() to onSubmit and then chain on it (or use await there):
const login = (user, password) => {
const body = {
username: user,
password: password,
};
return axios
.post('/sessions', body, {
headers: { 'Content-Type': 'application/json' },
})
.then((resp) => {
dispatch({ type: LOGIN, payload: resp.data.data });
})
.catch((err) => {
console.log(err.response.data);
});
};
// Option 1:
const onSubmit = (e) => {
e.preventDefault();
login(user, password)
.then(() => {
console.log(credes);
});
};
// Option 2:
const onSubmit = async (e) => {
e.preventDefault();
await login(user, password);
console.log(credes)
}
Related
i want to navigate to dashboard after login and dashboard is protected route
const handleLogin = (e) => {
e.preventDefault();
if (email || password) {
dispatch(loginUser({ email, password }));
navigate("/dashboard");
} else {
toast.error("Please Enter Email and Password");
}
};
i am using redux toolkit createAsyncThunk for api request
export const loginUser = createAsyncThunk("auth/login", async (userDetails) => {
try {
const { email, password } = userDetails;
const res = await fetch("http://localhost:5000/api/users/login", {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
}),
});
const result = await res.json();
if (result.error) {
toast.error(result.error);
} else {
toast.success("Login successfull");
localStorage.setItem("user", JSON.stringify(result));
return result;
}
} catch (error) {
console.log(error);
}
});
when i click on login it try to navigate the page before the state update what i want the navigate function wait untill the api respone recieve then navigate to dashboard
dispatch(loginUser({ email, password })); returns a promise, you can wait for the promise to resolve before doing additional work:
const handleLogin = () => {
dispatch(loginUser({ email, password })).then(() => {
navigate("/dashboard");
})
}
see Unwrapping Result Actions
On my console log, i can see my object for my response.json but i think i forget something for my setUser because my object return undefined ?
function Profil() {
const [user, setUser] = useState({});
const getUser = () => {
const headers = new Headers({
"Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest",
Authorization: "Bearer " + localStorage.getItem("token"),
});
const options = {
method: "GET",
headers: headers,
};
fetch(
"https://..../user",
options
)
.then((response) => {
return console.log(response.json());
})
.then(
(responseObject) => {
const userData = responseObject;
setUser({ ...user, userData });
console.log(user);
},
(error) => {
console.log(error);
}
);
};
useEffect(() => {
getUser();
}, []);
return (
<div>
<h1> Prénom</h1>
</div>
);
}
export default Profil;
my object on my console log is
[[PromiseResult]]: Object
email: "test#gmail.com"
firstname: "test"
lastname: "test"
_id: "61519405b8dc4a001be666"
You're returning undefined from your Promise:
.then((response) => {
return console.log(response.json());
})
response.json() itself returns a Promise, so return that:
.then((response) => {
return response.json();
})
There's no need to log the Promise itself. If you want to log the raw response JSON to the console then do that in the next Promise:
.then(
(responseObject) => {
// here:
console.log(responseObject);
const userData = responseObject;
setUser({ ...user, userData });
console.log(user);
},
(error) => {
console.log(error);
}
);
Additionally, be aware of what this is doing:
console.log(user);
This will log the state of user when this code is running. It will not reflect the update from here:
setUser({ ...user, userData });
Because that state update happens asynchronously. If you want to log the updated state value, either do it in a useEffect, or directly in the rendering of the component, or just log the object you're passing to setUser.
You also don't need your userData variable at all. It adds no value and is just a reference to responseObject.
Initially I write my code with promise based script .then().catch
But when I tried to change it into the async await function. Its not working anymore.
Please someone help me with this.
My Old Code Which is working
export const fetchToken = (params) => {
return (dispatch) => {
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
};
return axios
.post(`/api/token`, params, config)
.then((res) => {
tokenData = res.data.access_token;
dispatch({
type: LOGGED_IN,
payload: res.data,
});
})
.catch((err) => {
console.log(err);
alert('Provided username and password is incorrect');
throw err;
});
};
};
As you can see in the above code the function is returning a promise. But When I try to change it into async await
My simulator is give me Unexpected reserved work await Error
Here is my async await code in redux
export const fetchToken = async (params) => {
return (dispatch) => {
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
};
try {
const response = await axios.post(`/api/token`, params, config);
const data = await response.json();
tokenData = data.access_token
dispatch({ type: LOGGED_IN, payload: res.data})
} catch {
console.log(err);
alert('Provided username and password is incorrect');
}
};
};
Your async is applied to the wrong function, it should be on the dispatch function
export const fetchToken = (params) => (
async (dispatch) => {
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
};
try {
const response = await axios.post(`/api/token`, params, config);
const data = await response.json();
tokenData = data.access_token
dispatch({ type: LOGGED_IN, payload: res.data})
} catch {
console.log(err);
alert('Provided username and password is incorrect');
}
};
);
NB: I've removed the braces; arrow function return is implied https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
I am new to redux and
I am now trying to write a login component.
my redux actions is something like this.
export const fetchToken = (params) => {
return (dispatch) => {
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
};
return axios
.post(`${baseUri}/api/token`, params, config)
.then((res) => {
dispatch({
type: LOGGED_IN,
payload: res.data,
});
})
.catch((err) => {
console.log(err);
alert('Provided username and password is incorrect');
});
};
};
as you can see I am returning a promise. I try to use it in the component but it's not working.
I am using useDispatch hooks from react-redux
my code look like this
const checkValidate = () => {
if (email.length < 1 || password.length < 1) {
alert('Please fill all the details');
return;
} else {
const params = new URLSearchParams();
params.append('username', email);
params.append('password', password);
params.append('grant_type', 'password');
dispatch(fetchToken(params)).then((res) => {
alert('success')
}).catch((err) => alert('not success'));
}
// navigation.navigate('Home');
};
As you can see I am alerting the success. The problem is that if I write the wrong username and password. The response always goes into success response. It will alert success then It will alert the response from the fetchToken action which is alert('Provided username and password is incorrect'); Is there anything wrong with my code.
And also whenever I try to console.log the then response it will always return undefined
When you do
.then((res) => {
dispatch({
type: LOGGED_IN,
payload: res.data,
});
})
.catch((err) => {
console.log(err);
alert('Provided username and password is incorrect');
});
you remove the error and the result from the chain. If you want them to be passed to the next .then or .catch, you have to return/rethrow it:
.then((res) => {
dispatch({
type: LOGGED_IN,
payload: res.data,
});
+ return res
})
.catch((err) => {
console.log(err);
alert('Provided username and password is incorrect');
+ throw err
});
I changed my code to handle API errors in one place and it stops working, can anyone identify what is the problem
before changing (working fine)
action.js
export const login = (email, password) => dispatch => {
axios
.post('http://localhost:8000/v1/users/signin/', {
email: email,
password: password,
})
.then(res => {
dispatch({
type: LOGIN_USER,
payload: res.data,
});
})
.catch(err => console.log(err));
};
after changing my code
action.js
import { postRequest } from '../services';
export const login = (email, password) => dispatch => {
postRequest('users/signin/', {
email: email,
password: password,
})
.then(res => {
dispatch({
type: LOGIN_USER,
payload: res.data,
});
})
.catch(err => console.log(err));
};
services.js
export const API_URL = 'localhost:8000/v1/';
export const postRequest = (request, body) => {
return axios.post(API_URL + request, body);
};
Did you forget 'http:' on API_URL?
export const API_URL = 'http://localhost:8000/v1/';