Convert fetch actions to axios actions - reactjs

I'm trying to update my actions to axios from fetch.
For example my current login looks like this:
export const login = (email, password) => {
return (dispatch) => {
dispatch({
type: 'CLEAR_MESSAGES'
});
return fetch('/login', {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: email,
password: password
})
}).then((response) => {
if (response.ok) {
return response.json().then((json) => {
dispatch({
type: 'LOGIN_SUCCESS',
token: json.token,
user: json.user
});
cookie.save('token', json.token, { expires: moment().add(1, 'hour').toDate() });
browserHistory.push('/account');
});
} else {
return response.json().then((json) => {
dispatch({
type: 'LOGIN_FAILURE',
messages: Array.isArray(json) ? json : [json]
});
});
}
});
};
}
So far for the conversion to axios, I have this:
export const login = (email, password) => {
// const { email, password } = this.props;
(dispatch) => {
dispatch({
type: 'CLEAR_MESSAGES'
})
axios({
method: 'post',
url: '/login',
data: { email: email, password: password }
}).then((response) => {
dispatch({
type: 'LOGIN_SUCCESS',
token: json.token,
user: json.user
});
cookie.save('token', json.token, { expires: moment().add(1, 'hour').toDate() });
browserHistory.push('/account');
})
.catch(() => dispatch({
type: 'LOGIN_FAILURE',
messages: Array.isArray(json) ? json : [json]
})
)
}}
Its not working :( and I'm not sure what I'm doing wrong - not too familiar with axios.
I'm getting this error in Google Chrome console

I believe the error is cause you're calling a json variable that is not present in your updated code.

You need to access the data via response.data. When using fetch() it made sense to convert the response with response.json() and use a thenable to tap into that json, but with axios, you can reach into the response right away without any conversions.
export const login = (email, password) => {
return (dispatch) => {
dispatch({
type: 'CLEAR_MESSAGES'
})
axios.post("/login", {email, password}).then((response) => {
dispatch({
type: 'LOGIN_SUCCESS',
token: response.data.token,
user: response.data.user
});
cookie.save('token', json.token, { expires: moment().add(1, 'hour').toDate() });
browserHistory.push('/account');
})
.catch(() => dispatch({
type: 'LOGIN_FAILURE',
messages: Array.isArray(json) ? json : [json]
})
)

Related

react-admin useGetIdentity return only the fullname, id is undefined avatar is undefined

my app is based on tutorial of React-admin and loopback 4 as a backend
I'm trying to get the id of the logged in user, the login mechanisms works well but when i try to access the id of the logged in user it remains undefined.
in my authProvider, my login function is
login: ({ username, password }) => {
const request = new Request(
process.env.REACT_APP_API_URL + '/users/login',
{
method: 'POST',
body: JSON.stringify({ email: username, password }),
headers: new Headers({ 'Content-Type': 'application/json' }),
},
);
return fetch(request)
.then((response) => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then((auth) => {
localStorage.setItem(
'auth',
JSON.stringify({ ...auth, fullName: username }),
);
})
.catch(() => {
throw new Error('Network error');
});
},
and I use this in one component:
const CurrentUserId = ({ id }) => {
const { identity, isLoading: identityLoading } = useGetIdentity();
console.log(identity);
if (identityLoading) {
return <span>Loading...</span>;
} else {
// find the user_id from the identity
const user_email = identity.fullName;
const user_id = identity.id;
return <span>id: {user_id}</span>;
}
};
but the I console.log returns
{id: undefined, fullName: 'xxx#xxxxx.com', avatar: undefined}
I followed the instructions presented here
https://marmelab.com/react-admin/AuthProviderWriting.html
https://marmelab.com/react-admin/useGetIdentity.html
any ideas how to retrieve the id?
thanks a lot
If you receive a JWT token from the server, you need to decode it and store it like this:
import jwtDecode from 'jwt-decode'
...
function saveLBToken({ token } : { token: string }) {
const decoded = jwtDecode(token)
if (decoded && typeof decoded === 'object') {
sessionStorage.setItem(LB4_TOKEN, JSON.stringify({ token, ...decoded }))
} else {
console.log('Bad LB token:', decoded)
}
}
Thanks to MaxAlex answer I ended up using this in my code:
export const authProvider = {
// authentication
login: ({ username, password }) => {
const request = new Request(
process.env.REACT_APP_API_URL + '/users/login',
{
method: 'POST',
body: JSON.stringify({ email: username, password }),
headers: new Headers({ 'Content-Type': 'application/json' }),
},
);
return fetch(request)
.then((response) => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then((auth) => {
const { id, name, email, exp, iat } = jwtDecode(auth.token);
if (!id || !name || !email || !exp || !iat) {
throw new Error('Invalid token');
}
if (exp < iat) {
throw new Error('Token expired');
}
localStorage.setItem(
'auth',
JSON.stringify({
...auth,
id,
fullName: name,
email,
exp,
iat,
}),
);
})
.catch(() => {
throw new Error('Network error');
});
},

Cannot read property of "undefined": POST request from React to Express

I have this controller to authenticate a user by their email and password
const authUser = asyncHandler(async (req, res, next) => {
console.log('Hit');
const { email, password } = req.body;
await User.findOne({ email }, async (err1, foundUser) => {
if (err1) {
next(err1);
} else if (foundUser && (await foundUser.matchPasswords(password))) {
res.json({
_id: foundUser._id,
name: foundUser.name,
email: foundUser.email,
token: generateWebToken(foundUser._id),
});
} else {
res.status(401);
next(new Error('Invalid credentials'));
}
});
});
where the mongoose instance method matchPasswords is defined as
userSchema.methods.matchPasswords = async function (enteredPassword) {
return await bcrypt.compare(
enteredPassword,
this.password,
(err, success) => {
console.log(success);
return success;
}
);
};
In the React frontend I have created an action creator loginUser like so
export const loginUser = ({ email, password }) => async (dispatch) => {
try {
dispatch({ type: USER_LOGIN_REQUEST });
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const { data } = await axios.post(
'/api/v1/users/login',
{ email, password },
config
);
dispatch({
type: USER_LOGIN_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: USER_LOGIN_FAIL,
payload:
error.response && error.response.data.message
? error.response.message.data
: error.message,
});
}
};
However, when I try to login with the wrong credentials or the correct ones I receive this message in the screen and console Uncaught (in promise) TypeError: Cannot read property 'data' of undefined. Above that there is this error main.js?attr=bsXXNSP9r2dL_fbuBOkoev2GjgusyPgY7MC7K-twziLtf_MItBzQdXJ4l_HgsPQw:2699 POST http://localhost:3000/api/v1/users/login 401 (Unauthorized) which made me think maybe it's proxy error because my server is running on port 5000, but the console.log('Hit'); inside the authUser controller is fired when I make the request, which means the request reaches the backend, but there is some uncaught error. Where is my mistake?

How to present API response with redux and react

I am new to front-end. I use react and redux-form after I subbmit form on backend don't know how to handle response and present it with react. My response is simply only one number.
return function (dispatch, getState) {
dispatch({
type: CHANGE_ID_SUBMIT_DATA,
});
let reqBody = {
firstname: changeId.firstName
username: cnahgeId.userName,
};
return fetch(`${__REST_HOST__}/test/api/change/id`, {
credentials: 'include',
method: 'post',
headers: {
'Accept': 'application/json;charset=UTF-8',
'Content-Type': 'application/json;charset=UTF-8',
},
body: JSON.stringify(reqBody),
}).then(
response => dispatch(receiveData(response)),
error => dispatch({
type: CHANGE_ID_RESPONSE_ERR_DATA,
error
})
);
};
}
function receiveData(resp) {
console.log(resp.text());
return resp.text().then(response => dispatch({
type: CHANGE_ID_RESPONSE_DATA,
newId: response,
receivedAt: moment(Date.now())
}));
}```

How to convert fetch to axios in raectjs?

As i just know basic of axios and not able to convert this fetch to axios method. I have the following piece of code which is working perfect i am confused do i need to use Json.stringify or any other json method as what i have read is axios do automatically converts to json
here is my code
const handleFormSubmit = event => {
event.preventDefault();
setData({
...data,
isSubmitting: true,
errorMessage: null
});
fetch("https://hookedbe.herokuapp.com/api/login", {
method: "post",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
username: data.email,
password: data.password
})
})
.then(res => {
if (res.ok) {
return res.json();
}
throw res;
})
.then(resJson => {
dispatch({
type: "LOGIN",
payload: resJson
})
})
.catch(error => {
setData({
...data,
isSubmitting: false,
errorMessage: error.message || error.statusText
});
});
};
changing it to axios
const url = "https://hookedbe.herokuapp.com/api/login"
const body = {
username: data.email,
password: data.password
};
axios.post(url, body)
.then(res => {
dispatch({
type: "LOGIN",
payload: res.data
})
})
.catch(error => {
console.log(error);
})
You can use axios.post, much easier syntax and no need for any json conversion:
const payload = {
username: data.email,
password: data.password
};
axios.post("https://hookedbe.herokuapp.com/api/login", payload)
.then(res => {
dispatch({
type: "LOGIN",
payload: res.data
})
})
.catch(error => {
console.log(error);
})

ReactJS - Replacing a fetch API with axios is not working

I have a block of code in ReactJS with FETCH api that is working perfectly fine but when I tried to replace it with AXIOS then its not functioning perfectly, even though I checked the documentation.
WORKING CODE OF FETCH API:
const signup = (user) => {
return fetch(`${API}/signup`, {
method: "POST",
headers: {
Accept: 'application/json',
"Content-Type": 'application/json'
},
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.catch(err => {
console.log(err);
});
}
const clickSubmit = (event) =>{
event.preventDefault();
signup({name, email, password})
.then(data => {
if(data.error){
setValues({...values, error: data.error, success: false})
}
else{
setValues({...values, name: '', email: '', password: '', error:'', success:true})
}
})
}
NOT WORKING SAME CODE BUT WITH AXIOS LIBRARY:
import axios from 'axios';
const signup = (user) => {
return axios(`${API}/signup`, {
method: "POST",
headers: {
Accept: 'application/json',
"Content-Type": 'application/json'
},
data: JSON.stringify(user)
})
.then(response => {
return response.data;
})
.catch(err => {
console.log(err);
});
}
const clickSubmit = (event) =>{
event.preventDefault();
signup({name, email, password})
.then(data => {
if(data.error){
setValues({...values, error: data.error, success: false})
}
else{
setValues({...values, name: '', email: '', password: '', error:'', success:true})
}
})
}
The error that is coming after writing the above code with axios library is:
Unhandled Rejection (TypeError): Cannot read property 'error' of undefined
What is wrong in the code with axios ?
Note:
Apparently I narrowed it down to the place where undefined is coming.
signup({name, email, password})
.then(data => {
if(data.error){
setValues({...values, error: data.error, success: false})
}
else{
setValues({...values, name: '', email: '', password: '', error:'', success:true})
}
})
}
Here in the .then() block 'data' is coming as undefined and I don't know why as with fetch api its working fine.
Reference the documentation of Axios found here: https://github.com/axios/axios#response-schema
What you are missing is
.then(response => {
return response.data;
})
instead of:
.then(response => {
return response;
})

Resources