Possible unhandled promise rejection react-native - reactjs

In my dataloader the response I get I do this :
method: 'PUT'
})
.then(response => response.json().then(json => {
response.ok ? json : Promise.reject(json)}))
.then(schematizeResponse)
On my Screen I have a button that dispatches the function and which is :
_updateValues(){
try{
//update Email
this.props.editProfile({
currentUserToken: this.props.userSession.currentUserToken,
data: {
email: this.state.newEmail
}
})
this.state.updated= true;
}
catch(e) {
this.state.updated= false;
}
When the response fails, I get :
Possible unhandled promise rejection (id:0 ) and the response body.
The editProfile that I call through props is in my controller :
function mapDispatchToProps(dispatch) {
return {
dispatch,
editProfile: bindActionCreators(editProfileRequest, dispatch)
};
}
Update :
this.props.editProfile({
currentUserToken: this.props.userSession.currentUserToken,
data: {
email: this.state.newEmail
}
})
Here i need :
try {
this.props.editProfile({
currentUserToken: this.props.userSession.currentUserToken,
data: {
email: this.state.newEmail
}
})
}
catch( error ? )
{
this.setState({failedUpdate:true})
}
How do I handle the rejection ?

You have the order wrong in your fetch. Try this:
method: 'PUT'
})
.then(response => {
if (response.ok)
return response.json()
else throw new Error('error')
.then(schematizeResponse).
catch(err => alert(err));

Related

Unhandled Runtime Error TypeError: events.map is not a function

I'm fetching data using graphQL but wen I render in the page
it says Unhandled Runtime Error TypeError: events.map is not a function
useState don't know if this correct?
const [events, setEvents] = useState < any > ([]);
const fetchEvents = async () => {
const requestBody = {
query: `
query{
events{
_id
title
date
price
description
creator {
_id
email
}
}
}
`
};
setLoading(true);
await fetch(`http://localhost:8888/graphql`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
}).then(res => {
if (res.status !== 200 && res.status !== 201) {
throw new Error('Failed!');
}
return res.json();
}).then(resData => {
//console.log(resData);
const events = resData.data.events;
setEvents({ events: events })
}).catch(err => {
console.log(err);
})
}
{
loading ? events.map((data: any, index: any) =>
<p key={index}>{data.title}</p>
)
:
<p>Loading</p>
}
my console.log
You are getting "TypeError: events.map is not a function" error because events is an object, not an array. You are using setEvents({ events: events }) instead of setEvents(events) to set the state.
Changing setEvents({ events: events }) to setEvents(events) should fix it.
You should set the loading to false once you receive the desired response. You should also access the events by using events.events (or better use setEvents(events)).
const fetchEvents = async () => {
const requestBody = {
query: `
query{
events{
_id
title
date
price
description
creator {
_id
email
}
}
}
`
};
setLoading(true);
await fetch(`http://localhost:8888/graphql`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
}).then(res => {
if (res.status !== 200 && res.status !== 201) {
throw new Error('Failed!');
}
return res.json();
}).then(resData => {
//console.log(resData);
const events = resData.data.events;
setEvents({ events: events });
// CHECK NEXT LINE
setLoading(false);
}).catch(err => {
console.log(err);
})
}
Then you should change your React component to render the list only when loading is set to false. I also think (not sure cause you didn't submitted the full code) that you have to access the events using events.events.map
{!loading ? events.events.map((data: any, index: any) =>
<p key={index}>{data.title}</p>
)
:
<p>Loading</p>
}

Fetch API React Js Unexpected token < in JSON at position 0

I got this error from my fetch api when I pass my url fetch API from a state called url. But when I changed my url into text like 'api/provinsi' I don't get any error
Error fetching data: SyntaxError: Unexpected token < in JSON at
position 0
useEffect(() => {
async function fetchMyAPI() {
await fetch(url, {
method: 'GET'
}).then(response => {
if(!response.ok) {
throw new Error(response.statusText);
}
return response.json();
})
.then(response => {
if(response.Response === 'False') {
throw new Error(response.Error);
}
setData(response.data);
}).catch(error => {
console.log("Error fetching data: ", error);
});
}
fetchMyAPI();
}, []);
And this is how I set my url state:
useEffect(() => {
if(idDaerah==1){
setColumn(['no', 'nama', 'aksi']);
setUrl('/api/provinsi');
} else if(idDaerah==2) {
setColumn(['no', 'nama', 'provinsi_id', 'aksi']);
setUrl('/api/kabupaten');
} else if(idDaerah==3) {
setColumn(['no', 'nama', 'kabupaten_id', 'aksi']);
setUrl('/api/kecamatan');
} else {
setColumn(['no', 'nama', 'kecamatan_id', 'aksi']);
setUrl('/api/desa');
}
}, []);
Because both useEffect runs at the same time, and the fetch function receive url as an empty string first time, so you need to add url as dependency.
useEffect(() => {
async function fetchMyAPI() {
await fetch(url, {
method: 'GET'
}).then(response => {
if(!response.ok) {
throw new Error(response.statusText);
}
return response.json();
})
.then(response => {
if(response.Response === 'False') {
throw new Error(response.Error);
}
setData(response.data);
}).catch(error => {
console.log("Error fetching data: ", error);
});
}
if(url !== ''){ //check if url is set i.e not an empty string
fetchMyAPI();
}
}, [url]); //add dependency, when url change then call api
OR
You can provide a default url like:
const [url, setUrl] = useState('/api/provinsi');

How to return API data to a separate component - React Native

I am Fetching data from an API in my Native App and displaying it as a List.
Below is my code:
async componentWillMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('hardwareBackPress', this.backPressed);
}
this.fetchNotifications();
}
}
async fetchNotifications() {
this.setState({refreshing: true});
const config = getAppConfig();
const cognitoToken = await this.getCognitoToken(config);
if (cognitoToken !== null) {
let headers = await this.getRequestHeaders(cognitoToken);
let body = this.getRequestBody(config);
let notificationUrl = config["notification-retrieve-api"];
return fetch(notificationUrl,
{
method: 'POST',
headers: headers,
body: body
}).then((response) => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong');
}
})
.then((notifications) => {
console.log(JSON.stringify(notifications));
this.setState({
notifications,
error: null,
refreshing: false
});
}).catch((error) => {
this.setState({
notifications: [],
error,
refreshing: false
});
});
}
}
This works fine. I can retrieve the data from the API.
Now I want to separate the API code from my screen component. I will be calling "fetchNotifications" as a function in my screen component. I am trying to do so but it's not working at all.
This is what I'm doing:
async componentWillMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('hardwareBackPress', this.backPressed);
}
let response = fetchNotifications();
this.setState({
notifications: response,
error: null,
refreshing: false
})
}
}
async function fetchNotifications() { //now this function is in another component
.
.
.
.
if(cognitoToken !== null) {
let headers = await this.getRequestHeaders(cognitoToken);
let body = this.getRequestBody(config);
let notificationUrl = config["notification-retrieve-api"];
return fetch(notificationUrl,
{
method: 'POST',
headers: headers,
body: body
}).then((response) => {
if (response.ok) {
response.json();
} else {
throw new Error('Something went wrong');
}
})
.then((response) => {
return response;
}).catch((error) => {
this.setState({
notifications: [],
error,
refreshing: false
});
});
}
}
export default fetchNotifications;
Is this way correct? Anyone with a better solution?
My two cents, I always put async task in Promise, including API requests.
// API helper file
export const fetchNotifications = (params) => {
return new Promise(async (resolve, reject)=>{
try{
const headers = getHeaders(params)
const body = getBody(params)
const response = await fetch(notificationUrl,
{
method: 'POST',
headers: headers,
body: body
})
if (response.ok) {
const responseObj = await response.json();
resolve(responseObj)
} else {
throw new Error('Something went wrong');
}
} catch (e) {
// something went wrong
generalHandler(e) // logging etc.
reject(e) // for ui handling
}
}
}
then we can use it everywhere
import { fetchNotifications } from '.../APIHelper'
In your ui file :
componentWillMount() {
fetchNotifications(params)
.then((notifications) => {
console.log(JSON.stringify(notifications));
this.setState({
notifications,
error: null,
refreshing: false
});
}).catch((error) => {
this.setState({
notifications: [],
error,
refreshing: false
});
});
}

why axios return promise error in reactjs

i got error every time i click button on sign-in
TypeError: Cannot read property 'then' of undefined
, but after reload error gone. can i know what happened? here's my code on login
onSignIn(e){
e.preventDefault()
this.Auth.login(this.state.signInUsername, this.state.signInPassword)
.then(res => {
this.props.history.replace('/')
})
.catch(err => {
alert(err)
})
}
and this is my auth code:
login(username, password){
axios.post('http://localhost:3000/user/login', {
username,
password
})
.then(this._checkStatus)
.then(res => {
if(res.data.success === true){
const payload = {
name: username,
}
this.setToken(payload)
return Promise.resolve(res)
}else{
console.log(res.data.message)
}
})
.catch(err => {
return Promise.reject(err)
})
}
return axios from login function.
login(username, password){
return axios.post('http://localhost:3000/user/login', {
username,
password
})
.then(this._checkStatus)
.then(res => {
if(res.data.success === true){
const payload = {
name: username,
}
this.setToken(payload)
return res;
}else{
console.log(res.data.message)
}
})
.catch(err => {
throw err;
})
}
I believe you have -two- ".then" for your axios.post.The example provided at axios site uses
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
just one .then per axios call.

Handle Error response React.js

My Spring boot Controller method:
#RequestMapping(value = "/test", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<APIResponseMessage> testMethod(#RequestBody MyPojo myPojo) {
APIResponseMessage resp = new APIResponseMessage();
try {
serviceObj.callServiceMethod(myPojo);
resp.setMessage("successfull!");
} catch (Exception e) {
resp.setMessage("failed!");
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(resp);
}
return ResponseEntity.ok(resp);
}
React action handler class has the following method:
export default (data) => (dispatch) => {
dispatch({
type: initHandler
});
fetchJSON(url, 'POST', data)
.then((json) => {
dispatch({
type: successHandler,
apiResponse: json
})
})
.catch((error) => {
dispatch({
type: failureHandler,
apiResponse: error,
apiMessage : "System encountered error. Please try again later."
})
})
}
And fetchJSON is define in one of my util classes in react as :
export const checkStatus = response => {
const hasError = (response.status < 200 || response.status >= 300)
if (hasError) {
const error = new Error("This is an error") // I want to set my message that I obtained from the controller here.
throw error
}
return response
}
export const parseJSON = response => response.json()
export const fetchJSON = (url, method, data) => {
return fetch(url, {
method: method,
headers: new Headers({
'Content-Type': 'application/json'
}),
body: JSON.stringify(data)
}).then(checkStatus).then(parseJSON);
}
I want to set the custom message that I get from my API to be set to the error object. I tried many options but couldn't make it to work.
The problem is how the Promise is being resolved, or rather, not resolved when you try to use it. Calls to 'response.json()' return a promise, during the normal flow of execution when you don't 'throw' an error, this promise is resolved, and you can work with the result.
However, when the error is thrown, you need to resolve, or '.then()' the error in the catch block.
I think this should work for you, first throw your response.text() in the checkStatus function:
if (hasError) {
throw response.json()
}
Since you are throwing an error in a Promise, the nearest catch, or rejection callback is invoked:
.catch((error) => {
dispatch({
type: failureHandler,
apiResponse: error,
apiMessage : "System encountered error. Please try again later."
})
})
'error' in this case is the unresolved Promise created by calling 'response.text()', so you can resolve this by wrapping the 'dispatch' in error.then() as follows:
.catch((error) => { // error is a Promise
error.then((e) => {
dispatch({
type: failureHandler,
apiResponse: e, // e is now the resolved value of 'response.text()'
apiMessage : "System encountered error. Please try again later."
});
});
})
There is a simplified jsfiddle of this here: https://jsfiddle.net/LLL38vea/

Resources