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

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');

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>
}

Error handling axios request with recursion

I have a use effect with the helper function registerAccountInConfigurator(token)
acquireTokenForScope([`${process.env.REACT_APP_SW_SCOPE}`]).then(
(token) => {
if (token) {
// console.log(registerAccountInConfigurator(token));
registerAccountInConfigurator(token).then(function (response) {
console.log("response arrived ", response);
});
}
return null;
}
);
In case of an error in the helper function I want to do some steps and then call the function again.
export async function registerAccountInConfigurator(
adb2cToken: string,
change: any = false,
account?: any
) {
try {
const contextRes = await axios.get(
`${process.env.REACT_APP_SW_BASE_URL}/context`,
{
headers: change
? {
"sw-access-key": process.env.REACT_APP_SW_ACCESS_KEY ?? "",
...(adb2cToken !== "" && {
Authorization: `Bearer ${adb2cToken}`,
}),
}
: {},
}
);
const context: any = { ...contextRes.data };
const response = await axios.post(
`${process.env.REACT_APP_SW_BASE_URL}/post-ecommerce/account/register`,
account ?? { storefrontUrl: window.origin },
{ headers: headers(context.token, adb2cToken) }
);
const newToken = response.headers["sw-context-token"];
localStorage.setItem(SW_CONTEXT_TOKEN, newToken);
return response.data;
// Promise.resolve(response.data);
// return new Promise((resolve, reject) => {
// return resolve(response.data);
// });
} catch (error) {
console.log(error);
// do some steps
await registerAccountInConfigurator(adb2cToken, true);
}
}
To artficially test it with an 401 Error I use the paramater change which is per default false and will be set to true in the catch block.
What I dont understand is when I call console.log("response arrived ", response); with setting change to true. I get a normal response, an object. When I set change to false, triggering the catch block, I get undefined as the response value in console.log("response arrived ", response); why is that happening? How can i change that?

async function in react component isn't working when triggered from the axios request

network.services.js
axiosCall = (axiosURL) => {
// const axiosURL = "https://api.github.com/user"
axios.get(axiosURL, {
headers: {
'Authorization': `qwdvryjutmnevw`,
}
}).then((res) => {
console.log(res.data);
return res.data;
}).catch((error) => {
throw error.message;
// console.error(error);
// toast.error(error.message);
})
}
component.js
const getData = async () => {
const asyncExample = async () => {
const result = await networkServices.axiosCall("/api/v1/calendars");
const responseData = await result;
console.log(responseData);
return responseData;
}
const data = asyncExample()
data.then(function(result) {
console.log(result); // "Some User token"
})
}
Trying to get data from service to my component in const result, console form service is consoling data but component is always returning undefined instead of data from the service file. SetTimeout function is also not working in component.
You have many mistakes. I advise you to take a look at documentation about Promises
First one:
You don't return data in axiosCall
A way to return data:
axiosCall = (axiosURL) => new Promise((resolve, reject) => {
axios.get(axiosURL, {
headers: {
'Authorization': `yourTokenHere`,
}
}).then((res) => {
// return a response data
resolve(res.data);
}).catch((error) => {
// return only error message
reject(error.message);
})
})
to use axiosCall:
try {
// don't forgot to configure axios with base url
const data = await axiosCall('/api/v1/calendars');
// do something with your data
} catch (e) {
// do something with error message
console.log(e);
}
Second:
Your make mistakes when call async function
Look at this example:
const getData = () => {
networkServices
.axiosCall("/api/v1/calendars")
.then(function(result) {
// when promise resolve
console.log(result);
})
.catch(error => {
// when promise reject
console.log(error)
})
}

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.

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
});
});
}

Resources