Throwing cross origin error upon setting state using React hooks - reactjs

The following is my hook that calls my server and fetches data. after I receive a response from the server, I'm trying to set this response to my state.
const [userProfileData, setUserProfileData] = useState({})
useEffect(() => {
const profileRequestBody = `
query{
GetUserAndProfileData{
name
email
_id
figsList{
_id
figData
createdAt
}
}
}
`
const usertoken = token
axios({
method: 'POST',
url: 'http://localhost:5000/graphql',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${usertoken}`
},
data: {
query: profileRequestBody
}
}).then(response => {
debugger
//check if we recieved any errors in the request
setIsLoading(false)
setUserProfileData(response.data.data.GetUserAndProfileData)
let errors = response.data.errors
console.log(errors)
if (errors) {
throw new Error(errors[0].message)
}
}).catch(err => {
debugger
console.log(err)
})
}, []);
setUserProfileData(response.data.data.GetUserAndProfileData) is throwing the following error A cross-origin error was thrown. React doesn't have access to the actual error object in development. I'm actually setting state there.

The issues is not about
setUserProfileData(response.data.data.GetUserAndProfileData)
when A cross-origin error was thrown. React doesn't have access to the actual error object in development. occur, this is because when you render the data in view are in object format instead of the primitive format (e.g. int, string, float), I can give you a example
Data json format:
[
{
"name":"micky",
"age":29,
"sex":"M",
"families":[
{
"name":"carol",
"age":30,
"sex":"F"
}
]
}
]
Code :
export default function (props) {
const [data, setData] = React.useState([]);
React.useEffect(() => {
FamilyService.getdata().then(res => {
setData(res);
});
}, []);
const getdata = (row) =>{
var familymember = row.families.find(x => x.name.includes("carol"));
return familymember;
}
return (
<div>
{data.map((row, idx) => (
<span>{row.name}</span>
<span>{row.age}</span>
<span>{getdata(row)}</span>
))}
</div>
);
}
In above code
var familymember = row.find(x => x.families.includes("data"));
return familymember; <----- This code will cause error!!!!
Because it is return a object instead of a value, if I want to fix the error, it should use
return familymember.name;

Related

How do I assign a value from response to body for another post data?

so I have 2 post data functions, the first is to upload photo/file, another one is for add a document.
in the API for add document, there are 3 body that need to be filled. name(string), location(string), and photo(string).
I already created the function for upload photo, and I get the return link of the url path for photo.
My question is, how do I assign the link from url path to body add document for photo(string)?
json for add document :
json for uploaded photo:
code for upload photo:
try {
const postFileReq = await axios.post(
"https://spda-api.onrender.com/api/file/upload",
formData,
options
);
const postFileRes = await postFileReq.data.image;
if (postFileReq.status === 200) {
setPhotoUrl(postFileRes);
console.log("postFileRes", postFileRes);
// console.log("photoUrl", photoUrl);
}
} catch (error) {
const err = error as AxiosError;
console.log(err.response?.data);
}
code for add document:
try {
const postDocReq = await axios.post(
"https://spda-api.onrender.com/api/admin/documents",
{
name: field.name,
location: field.location,
photo: photoUrl,
},
{
headers: {
"Content-Type": "application/json",
authorization: `Bearer ${token}`,
},
}
);
const postDocRes = await postDocReq.data;
if (postDocReq.status === 200) {
setShowSnackbar(true);
router.reload();
console.log(postDocRes);
}
} catch (error) {
const err = error as AxiosError;
console.log(err.response?.data);
}
i already tried using useState to assign but it still not working, anyone have an idea?
const [photoUrl, setPhotoUrl] = useState("");
My complete code: https://pastebin.com/Rb5xX08z
Alright so what you need you to do is call the second api in the success method of the first call. I will jump to the code directly with async/await. You can do it with then as well.
You can handle it inside your if condition 200 success. So like once it is successfull call the second function then. But I have shown with async/await like mentioned
import axios from 'axios'
const MyComponent = () => {
const [data, setData] = useState(null);
const [secondData, setSecondData] = useState(null);
const fetchData = async () => {
try {
const response = await axios.get('https://first-api.com');
setData(response.data);
//if first api was successful,call the second api
const secondResponse = await axios.get(`https://second-api.com/${response.data.id}`);
setSecondData(secondResponse.data);
} catch (error) {
console.error(error);
}
};
useEffect(() => {
fetchData();
}, []);
return (
<div>
<p>Data from first API: {JSON.stringify(data)}</p>
<p>Data from second API: {JSON.stringify(secondData)}</p>
</div>
);
};

REACT JS - Not able to set the state of an empty object to the response from the api

I am fetching json data from my local api but can't seem to assign it to the err state.
const [err, setErr] = useState({});
const host = "http://localhost:9000";
const addNote = async (obj) => {
const res = await fetch(`${host}/api/notes/addnote`, {
method : 'POST',
headers : {'Content-Type': 'application/json', 'auth-token' : 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFiQGdtYWlsLmNvbSIsImlhdCI6MTY3MTQ0ODMyOH0.sNTvl4L9HFaGPOmuSKpJMu418axsUmgDib-94ked3lQ'},
body : JSON.stringify(obj)
});
const data = await res.json();
console.log(data);
setErr(data);
console.log(err);
}
On logging data I get => {title:{msg :''}, description:{msg:''}}
On logging err I get => {}
useState() hook is asynchronous and will not reflect the update immediately. The value get's update in the next render and you can verify that with useEffect hook as shown below
useEffect(() => {
console.log(err) // prints the updated value
}, [err])
If you want the update to reflect immediately, you can use useRef() instead of useState().
Updated answer
I don't recommend using useRef() as it would force the updates between the renders which in turn effects the performance. If you want the errors to be displayed based on backend response, then don't render the component until you receive a response. Refer below code snippet
const [err, setErr] = useState({});
const [isDataLoading, setIsDataLoading] = useState(false);
const host = "http://localhost:9000";
const addNote = async (obj) => {
setIsDataLoading(true); // update loading state
const res = await fetch(`${host}/api/notes/addnote`, {
method : 'POST',
headers : {'Content-Type': 'application/json', 'auth-token' : 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFiQGdtYWlsLmNvbSIsImlhdCI6MTY3MTQ0ODMyOH0.sNTvl4L9HFaGPOmuSKpJMu418axsUmgDib-94ked3lQ'},
body : JSON.stringify(obj)
});
const data = await res.json();
setErr(data);
setIsDataLoading(false); // update loading state
console.log(data);
}
return (
{
isDataLoading ? <Loading /> : <YourComponent /> // if isDataLoading is true render some loading symbol else render your actual component.
}
)
const [err, setErr] = useState({});
const host = "http://localhost:9000";
const addNote = async (obj) => {
try {
const res = await fetch(`${host}/api/notes/addnote`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"auth-token":
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFiQGdtYWlsLmNvbSIsImlhdCI6MTY3MTQ0ODMyOH0.sNTvl4L9HFaGPOmuSKpJMu418axsUmgDib-94ked3lQ",
},
body: JSON.stringify(obj),
});
const data = await res.json();
if (res.status !== 200) {
// need to check object and set error as per object mappig
setErr(res.data);
}
} catch {
setErr('Api not workoing');
}
console.log(err);
};

json response from mock server not printing but is in the console

I am trying to learn react, and I am making a successful API call, but it only prints in the console. I found examples but many of them recommended to use setData(json) but I am not able to use it because the file is a list of export async function which was also recommended.
export async function GetHellWorld() {
return fetch(`http://localhost:8080/api`, {
method: "Get",
headers: {
"Content-type": "application/json; charset=UTF-8"
}
}).then(response => response.json())
.then(json => {
console.log(json)
})
.catch(error => (console.log(error)))
}
and the component
function Test(thisArg, argArray) {
const result = GetHellWorld.apply()
return (
<div className="App">
{JSON.stringify(result)}
</div>
);
}
export default Test;
In the console I see "Hello World" but in the browser is get just {}.
Two questions:
How can I bind the JSON response to an object so I can do something like result.name.
Is this the correct was to call the await function? const result = GetHellWorld.apply()
---- update ----
I decided to try axios because I want to make multiple calls in one file.
const axios = require('axios');
export class AppService {
public async GetHelloWorld(): Promise<any> {
const response = await axios.get(`http://localhost:8080/api`, {
method: "Get",
headers: {
"Content-type": "application/json; charset=UTF-8"
}
}).catch(() => console.log("Issue in GetHelloWorld"))
return response.data
}
}
component
import React from 'react';
import {AppService} from "../services/app.service";
function Movies() {
const api = new AppService()
const hello = async () => {
const response = await api.GetHelloWorld();
console.log("The response: " + response)
}
return (
<div className="App">
{JSON.stringify(hello)}
</div>
);
}
note I had to add typescript support.
For whatever reason I get
Module not found: Error: Can't resolve '../services/app.service' in '/Users/miketye/programming/test-react/src/components'
While the other answer about using a custom hook can work, I would not recommend it while you're still leaning React.
Look up how to use the "useEffect" hook, that's generally how you want to do any sort of loading logic in React.
First off, you need to fix your async function so it actually returns a value:
// style/convention note, but non-component functions should not start with a capital letter
export async function getHelloWorld() {
return fetch(`http://localhost:8080/api`, {
method: "Get",
headers: {
"Content-type": "application/json; charset=UTF-8"
}
}).then(response => response.json())
.then(json => {
return json // will cause this function to return a Promise of type "string", since we're in an async function
})
// better to just let the error get thrown here, for testing
}
Then use it like this:
function Test(thisArg, argArray) {
[fetchResult, setFetchResult] = useState(undefined) // look up useState. State is how you have values that change over time in a resct component
useEffect(() => {
async function fetchData() {
const data = await getHelloWorld()
setFetchResult(data)
}
fetchData()
}, [])
// look up useEffect. Since the second argument (the "dependency array") is empty, useEffect will fire only once, after the component loads
return (
<div className="App">
{result ? JSON.stringify(result) : "no result yet"}
</div>
);
}
export default Test;
You can use a custom hook for this purpose:
import { useState } from "react";
const useFetchData = () => {
const [data, setData] = useState(null);
const fetchData = () => {
fetch("http://localhost:8080/api", {
method: "Get",
headers: {
"Content-type": "application/json; charset=UTF-8"
}
}).then(response => response.json())
.then(json => { setData(json); })
.catch(error => { console.log(error); })
}
useEffect(() => {
fetchData();
}, []);
return { data, fetchData };
}
export default useFetchData;
And then call it in your component:
import useFetchData from "#/hooks/useFetchData";
const Test = () => {
const { data, fetchData } = useFetchData();
// CALL fetchData IF YOU WANT TO UPDATE THE CURRENT STATE
return (
<div className="App">
{data && JSON.stringify(data)}
</div>
);
}
export default Test;

React Typescript Mutation calling api every time the page is clicked

I have a simple page that calls an api to get some data and display it in a table. I use a function that uses mutation to call the api and return the data and the state of fetching the data. I use the following (pseudo) code to achieve this:
export const Instances = (props: InstanceProps) => {
const history =
useHistory<{
formId: number;
rowData: any;
formInstanceID: number;
}>();
const { isLoading, isError, isSuccess, data, error } = useGetFromApi('api/list', [
`${history.location.state.formId}`,
]);
if (isLoading) {
return (
<div>
Page Loading
</div>
);
}
if (isError) {
return (
<div>
An error occurred
</div>
);
}
if (isSuccess) {
if (data) {
// Map data to an array for the table component
}
}
return (
<div>
Display table showing data
</div>
);
};
The page calls the api successfully and displays the data in the table. The problem I have is when I click anywhere on the page or click the two buttons that are present on the page the mutation is called again and the page freezes while it fetches the data again. It doesn't remember that it's successfully loaded. How do I stop it from calling the api every time I interact with the page?
The code for the mutation function:
import { usePidgetIdentity } from '#workspace/utils-react';
import { useQuery } from 'react-query';
import config from '../shared/config';
export type ApiData = {
data: any[];
};
async function callToApi(url: string, getAccessToken: () => Promise<string>) {
const token = await getAccessToken();
console.log('Starting api fetch');
const response = await fetch(url, {
method: 'GET',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
});
console.log('Data has returned');
if (!response.ok) {
throw Error('An unexpected error occurred');
}
const apidata = await response.json();
return { data: apidata };
}
export function useGetFromApi(url: string, parameters: string[]) {
const { getAccessToken } = usePidgetIdentity();
let apiUrl: string = config.FORMS_API_URL + '/' + url;
parameters.map((parameter) => {
apiUrl += '/' + parameter.trim();
});
console.log('Calling ' + apiUrl);
return useQuery<ApiData, Error>(apiUrl, () => callToApi(apiUrl, getAccessToken));
}

UseEffect hook does not work or how to display async data

I am learning react and making a project that has a component that needs to display async information:
function ShortStatistic() {
const [coronaData, setCoronaData] = useState([]);
useEffect(() => {
(async () => {
const fetchedPosts = await getCoronaData();
setCoronaData(fetchedPosts);
})();
console.log("UseEffectCall");
}, []);
async function getCoronaData() {
const URL = "https://api.covid19api.com/summary";
const requestOptions = {
method: 'GET',
redirect: 'follow'
};
const response = await fetch(URL, requestOptions);
const data = await response.json();
return data;
}
return (
<div className="stat">
<div className="stat_infected">
Infected:
<span className="infected_numbers">
{(coronaData["Global"]["TotalConfirmed"])}
</span>
</div>
</div>
)
}
But I am getting an error: "TypeError: Cannot read property 'TotalConfirmed' of undefined", what means setCoronaData() didn't work. Also, there is no message output from the useEffect hook (console.log("UseEffectCall");) in the console. What is the problem?
for first render your coronaData variable is an empty array [] and when you call
coronaData["Global"]["TotalConfirmed"]
it means undefined
You can use
coronaData?.["Global"]?.["TotalConfirmed"]

Resources