React Native - Undefined is not an object when evaluating promise - reactjs

i am beginner react-native programmer . I am trying to return the responseJSON in a fetch function . I know it is asynchronous and will return promise, thus I need to use .then() , but when it says undefined is not an object.
here is the code
auth.js
export const onVerify = (email,password,navigation) => {
console.log('Verifying');
fetch('xxx',
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'email=' + email + '&password=' + password
})
.then((response) => response.json())
.then((responseJson) => {
if(responseJson.status == '200') {
Alert.alert(
'Login Successful',
'Welcome Home'
);
let data = {
name: responseJson.name,
id : responseJson.id
};
onSignIn();
return responseJson
}
in my signin.js
export default class SignIn extends React.Component{
step(){
onVerify(this.state.email,this.state.password,this.props.navigation).then(
function(data) {
console.log(data);
}
);
}

As said by #teivaz on the comment, your onVerify function returns nothing. Because the fetch call is asynchronous. So what you can do is return a Promise from onVerify then you'll be able to resolve it from step function.
This is how you can implement this,
export const onVerify = (email,password,navigation) => {
return new Promise((resolve, reject) => {
fetch('endpoint',
{
method,
headers,
body,
})
.then((response) => response.json())
.then((responseJson) => {
if(responseJson.status == '200') {
Alert.alert(
'Login Successful',
'Welcome Home'
);
let data = {
name: responseJson.name,
id : responseJson.id
};
onSignIn();
resolve(responseJson)
}
})
.catch(err => reject(err));
}
}
Also, make sure to catch the errors if any in step function.
export default class SignIn extends React.Component{
step(){
onVerify(this.state.email,this.state.password,this.props.navigation).then(
function(data) {
console.log(data);
}
)
.catch(err => console.log('Error occured', err));
}
}

Related

Axios does not catch error even not enter in catch block

I am trying to get the error status code that would be 413 in Axios catch block. I have tried different solutions nothing worked for me. Could you please review what is going wrong.
uploadNewDatDocuments(datId, files = [], additionalInfo = {}) {
return new Promise((resolve, reject) => {
let url = new URL(this.baseUrl + this.uploadDocument.replace('{id}', datId));
Object.keys(additionalInfo).forEach(queryParam => url.searchParams.set(queryParam, additionalInfo[queryParam]));
let formData = new FormData();
files.forEach(file => formData.append('files', file));
axios
.post(url.toString(), formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
resolve(response.data);
})
.catch(error => {
console.log("error occurred")
reject(error);
}).finally(error=>{
console.log(error);
})
});
}
Here is my Action code.
export function uploadNewDocuments(datId, additionalInfo = {}, attachments = [], comment = {}) {
return dispatch => {
datService
.uploadNewDatDocuments(datId, attachments, additionalInfo)
.then(response => {
const attachmentsIds = response.map(attachment => attachment.id);
dispatch(
DatCommentActions.addDatNewComment(datId, {
...comment,
message: { ...comment.message, attachments: attachmentsIds }
})
);
})
.catch(error => {
dispatch(MessageActions.showMessage({ message: error.response.data.message }));
console.error(error);
});
};
}
413 Request Entity Too Large is not actually error, its a not successful response and catch wont fire unless there is actual error on response.
What you could do is check response.status and based on that and write own error handling.

function is returning undefined while I am rexpecting some data

App.js
import { Component } from "react";
import "./App.css";
import checkUser from "./functions";
class App extends Component {
constructor() {
super();
console.log(checkUser('',''));
}
render() {
return (
<>
<h1 id="name">{this.user}</h1>
</>
);
}
}
export default App;
functions.js
let checkUser = (username, password) => {
let local_username = localStorage.getItem("username");
let local_token = localStorage.getItem("token");
let local_client_id = localStorage.getItem("client_id");
if (username === "" && password === "") {
fetch("/login?user=auth", {
method: "POST",
headers: {
username: local_username,
token: local_token,
client_id: local_client_id,
},
})
.then((data) => {
data.json();
})
.then((data) => {
return data
});
} else if (
username !== null &&
password !== null &&
local_client_id === null
) {
let res = fetch("/login?user=notloggedin", {
method: "POST",
headers: { username: username, password: password },
})
.then((res) => res.json())
.then((data) => {
if (data.status === true) {
localStorage.setItem("username", username);
localStorage.setItem("token", data.token);
localStorage.setItem("client_id", data.client_id);
return true;
} else {
return false;
}
});
}
};
export default checkUser;
I am expecting checkUser function to log user name but it is logging undefined.
It shows to request to server but not returning, I think that the problem is with the code in functions.js where I am returning something in a .then funtion.
In the first .then() you forget to return data.json(). you can either return:
.then((data) => {
return data.json();
})
//or wrap it in brackets so it automatically returns:
.then((data) => (
data.json();
))
//or make it one line:
.then((data) => data.json())

Fetch request is not updating the state

I have an react application connected to a database. Currently the app takes the database when it mounts and uses that to populate the state. The apps allows someone to post to the database. So far that works.
The issue is that I want the new posted content to be seen by the user. As it is the content only populates after I reload the page. I tried to repeat the coding in the componentDidMount() in a function that runs after the POST request, but for someone reason that is not working.
class App extends Component {
state = {
notes: [],
folders: [],
//noteID: 0,
//folderID: 0
};
componentDidMount() {
Promise.all([
fetch(`${config.API_ENDPOINT}/notes`),
fetch(`${config.API_ENDPOINT}/folders`)
])
.then(([notesRes, foldersRes]) => {
if (!notesRes.ok)
return notesRes.json().then(e => Promise.reject(e))
if (!foldersRes.ok)
return foldersRes.json().then(e => Promise.reject(e))
return Promise.all([
notesRes.json(),
foldersRes.json(),
])
})
.then(([notes, folders]) => {
this.setState({ notes, folders })
})
.catch(error => {
console.error({ error })
})
}
pageReload = () =>{
//console.log('pageReload ran');
Promise.all([
fetch(`${config.API_ENDPOINT}/notes`),
fetch(`${config.API_ENDPOINT}/folders`)
])
.then(([notesRes, foldersRes]) => {
if (!notesRes.ok)
return notesRes.json().then(e => Promise.reject(e))
if (!foldersRes.ok)
return foldersRes.json().then(e => Promise.reject(e))
return Promise.all([
notesRes.json(),
foldersRes.json(),
])
})
.then(([notes, folders]) => {
this.setState({ notes, folders })
})
.catch(error => {
console.error({ error })
})
}
folderSubmit = (f) => {
//console.log("folderSubmit ran " + f);
const newFolder = { "name" : f };
const postfolder = {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(newFolder)
};
fetch(`${config.API_ENDPOINT}/folders`, postfolder).then(this.pageReload())
}
It looks like you are not setting your state after post. see below where you need to set your state.
folderSubmit = (f) => {
//console.log("folderSubmit ran " + f);
const newFolder = { "name" : f };
const postfolder = {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(newFolder)
};
fetch(`${config.API_ENDPOINT}/folders`, postfolder)
.then(response => response.json())
.then(data => this.setState(data));
}

Unhandled Rejection (TypeError): Cannot read property 'error' of undefined

I'm fairly new to React and I've been trying to create a SignUp page, however, I'm stuck in this error. Can someone give me any indication on what I should do in order to solve this error?
Signup Method:
// = Action =
// Sign up
export 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));
}
Rewrite Signup method (ps: I only changed the .catch handler)
`
// Sign up
export 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));
return err;
}
`
You need to wrap up your fetch logic inside a Promise to return a value to the caller.
export const signup = user => {
return new Promise((resolve, reject) => {
fetch(`${API}/signup`,
{
method: 'POST',
headers: {
Accept:'application/json',
'Content-Type' : 'application/json'
},
body: JSON.stringify(user)
})
.then(response => response.json())
.then(jsonData => resolve(jsonData))
.catch(err => resolve({error: `something went wrong err : ${err}`}));
})
}
signup(user).then(data => {
if (data.error) {
// handle error case
} else {
// handle success case
}
})
Now your signup method will return a value. Your data variable won't be undefined anymore.
I hope it helps, feel free to add comments or ask me more details

problem with fetch in componentDidMount()

my list of users is undefined when i try to console.log it.
Maybe i didn't get something ?
I'd like to get my list of users from my api who works (tested with postman) and put it into the console next i'd like to map my users to show it on the app
class Test extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
}
}
componentDidMount() {
console.log("component did mount");
fetch("/user/list")
.then(res => {
return res.json();
})
.then(users =>
this.setState({users}, () =>
console.log("list of users => " + users)));
}
render() {
return (
<div className="form">
<ul>
{this.state.users.map((user) =>
<li key="user._id">{ user.name }</li>
)}
</ul>
</div>
);
}
} export default Test;
Thanks for help !
You are calling res.json() rather than returning res.json() from the first then on your fetch call
I've found this pattern to be helpful:
fetch(url)
.then(res => res.ok ? res.json() : Promise.reject())
As your code is now, users (the parameter in the second then would be undefined, because you are not returning anything from the first then
you have to return the res.json() to use it in the next .then()
.then(res => {
res.json();
})
should be
.then(res =>
res.json();
)
Or
.then(res => {
return res.json();
})
https://javascript.info/promise-chaining
You should be passing your res into res.json() and returning the results into your state.
componentDidMount() {
console.log("component did mount");
fetch("/user/list")
.then(res => res.json())
.then(users =>
this.setState(users,
() => {
console.log("list of users => " + users)
})
);
}
Michael Jasper response help me so much!
I found that fetch with GET method does not work if we pass any request body.
the full example is here
https://github.com/alexunjm/todo-list-react
const buildRequestOptions = ({
method = "GET",
raw = null, // I had my error here!, with GET raw need to be null
customHeaders = {name: 'value'},
}) => {
var myHeaders = buildHeaders(customHeaders);
var requestOptions = {
method,
headers: myHeaders,
body: raw,
redirect: "follow",
};
return requestOptions;
};
const listTasks = () => {
const url = `${uriBase}/task/sample`;
const requestOptions = buildRequestOptions({
customHeaders: { "Content-Type": "application/json" },
});
return fetch(url, requestOptions);
}
const asyncFn = ({
promiseToWait,
pendingFn,
successFn,
errorFn,
}) => {
return (dispatch) => {
dispatch(pendingFn());
promiseToWait
.then((res) => {
if (res.ok) {
return res.json();
}
// handled from server status 422 and 401
if (res.status === 422) {
// error message on body from server
return res.json();
}
if (res.status === 401) {
// custom error message hardcoded
return {errors: {action: 'no authorized'}}
}
console.log("http response no controlled", res);
return Promise.reject();
})
.then((body) => {
if (body.errors) {
const errors = Object.keys(body.errors).map(
(key) => key + " " + body.errors[key]
);
dispatch(errorFn(errors.join("; ")));
} else {
dispatch(successFn(body));
}
return body;
})
.catch((error) => {
console.log("error", error);
dispatch(errorFn("Unavailable server connection"));
});
};
};
const queryTasks = () => {
return asyncFn({
promiseToWait: listTasks(),
pendingFn: apiPending,
successFn: apiSuccessList,
errorFn: apiError,
});
}

Resources