How do I access API data in my HTML in react - javascript

I have been trying to access the API data inside my html code but I could not instead this error message keep showing.
This is the error
message: App.js:13 Uncaught TypeError: data.map is not a function
Here is the code snippet of the data fetching
export async function getUsers () {
try {
const response = await fetch('https://cornie-assessment.herokuapp.com/users/8wdkcw05bdEa47R')
return response.json()
} catch (err) {
console.log(err);
}
}
Then I imported it to my app.js file. Here is also the code
import { useEffect, useState } from 'react';
import {getUsers} from './Components/Request'
function App() {
const[data, setData] = useState([])
useEffect(() => {
getUsers().then(data => {
setData(data)
console.log(data)
})
}, [])
return (
<div className="App">
{
data.map(items => (
<article>{items.data.email}</article>
))
}
</div>
);
}
export default App;

Please check your API response and the data which you're setting to state.
map function work on an array.
As I have seen your API response -> It's an object type.
{"status": true, "data": [...], ...}
So, you should set the state like the below.
getUsers().then(res => {
setData(res.data) // it will be an array
console.log(res) // it's an object
})

Your response is an object { status : true, data: [...] }. You are using an array method ( map ) on the object. Try this
getUsers().then(response => {
setData(response.data)
})
}, [])

problem is related assigning the response data as array
export async function getUsers () {
try {
const response = await fetch('https://cornie-assessment.herokuapp.com/users/8wdkcw05bdEa47R')
const result = await response.json()
return result.data; // now you have an array of objects
} catch (err) {
console.log(err);
}

Related

Is it possible to call to APIs inside a react-router loader function

I'd like to know if it's possible to make 2 API calls inside a loader function if I am using react-router 6. My ideas was to create an object based on these 2 calls and destruct the object in the rendering component like this:
function MainComponent (){
const {data , reservation} = useRouteLoaderData('room-details');
..
..
}
export default MainComponent;
export async function loader({request, params}) {
const id = params.roomId;
const response = await fetch ('http://localhost:8080/rooms/' + id);
const response2 = await fetch('http://localhost:8080/rooms/reservation/' + id)
const megaResponse = {
data: response, //i tried data:{respose} It ain't work
reservation: response2,
};
if (!response.ok) {
throw json({message: 'Something Wrong'}, {status: 500});
}
else {
return megaResponse;
}
}
But i have no success output.
I'd really want to make these 2 call in one place, otherwise I will have to use useEffect in a child component. Not a good Idea I think.
Thanks
I suspect you are not returning the unpacked response, i.e. JSON. I suggest surrounding the asynchronous code in a try/catch and simply try to process the requests/responses. Unpack the JSON value from the response objects. Since it doesn't appear the requests are dependent on one another I recommend loading them into an array of Promises that can be run concurrently and awaited as a whole. If during any part of the processing a Promise is rejected or an exception thrown, the catch block will return the JSON error response to the UI, otherwise, the { data, reservation } object is returned.
const loader = async ({ request, params }) => {
const { roomId } = params;
try {
const [data, reservation] = await Promise.all([
fetch("http://localhost:8080/rooms/" + roomId),
fetch("http://localhost:8080/rooms/reservaton/" + roomId)
]).then((responses) => responses.map((response) => response.json()));
return { data, reservation };
} catch {
throw json({ message: "Something Wrong" }, { status: 500 });
}
};
I found the solution, I tried it and it worked. It is as follow:
function MainComponent (){
const [data , reservation] = useRouteLoaderData('room-details');
..
..
}
export default MainComponent;
export async function loader({request, params}) {
const id = params.roomId;
return Promise.all([
fetch ('http://localhost:8080/rooms/' + id),
fetch('http://localhost:8080/rooms/reservation/' + id)
])
.then(
([data, reservation]) =>
Promise.all([data.json(), reservation.json()]),
error => {throw json({message: 'Something Wrong'}, {status: 500});}
)
.then(([data, reservation]) => {
return [data, reservation];
});
}
Thanks

How do I conditionally render data returned from a useEffect that calls an API route and adds that data to a useState variable

I have a React component that's main purpose is to display a list of profile names. The profile names are stored in a useState variable called profiles.
I have a useEffect in place on the component that effectively calls our API route to return the profile data we need on the frontend and place that data in the state variable for profiles.
If the profiles state variable has a length of zero, then we don't have the data and a logo will appear to load, otherwise the profiles should be mapped through and displayed as h1 tags.
While a console.log shows to me I am returning the data I need, I am getting the following error in my console "Uncaught TypeError: profiles.map is not a function".
Here is my code:
function ProfileListComponent() {
const fetchProfiles = async (payload) => {
const token = localStorage.getItem("token")
const response = await axios.get("http://127.0.0.1:5000/profiles", {headers:{
"Authorization": `Bearer ${token}`
}})
if (response.data) {
let profileData = []
for (let key in response.data) {
let profile = [
response.data[key].profile_id,
response.data[key].profile_name,
response.data[key].flow_rate,
response.data[key].hv,
response.data[key].lv,
response.data[key].duty_cycle,
response.data[key].frequency,
]
profileData.push(profile)
}
console.log(profileData)
return profileData
}
}
const [profiles, setProfiles] = useState([])
const compileProfileData = () => {
return ""
}
useEffect(() => {
try {
const profileData = fetchProfiles()
setProfiles(profileData)
} catch (error) {
console.log(error)
}
}, [])
return (
<div>
{profiles.length === 0 ?
<img src={logo} className="App-logo" alt="logo" />
: (
profiles.map(profile => <h1 className="profileBox" key={profile[0]} onClick={() => {compileProfileData(profile)}}>{profile[1]}</h1>
)
)}
</div>
)
}
I have tried different methods to conditionally render this data, though I always seem to error out with the same message indicating that the state variable isn't even an array (which is interesting considering its default value is an empty array).
Does anyone have some guidance to offer on how to correctly get this data rendered?
This happens because inside useEffect hook try-catch block executes both fetchProfiles and setProfiles synchronously. So setProfiles sets a promise which has not resulted yet and below map function means "Give me array, not a promise".You should put your setState inside fetchProfiles.
From this;
const fetchProfiles = async () => {
// const profileData = await axios ...
return profileData;
};
useEffect(() => {
try {
const data = fetchProfiles();
setProfiles(data); // SETS HERE
} catch (error) {
console.log(error);
}
}, []);
To this;
const fetchProfiles = async () => {
// const profileData = await axios ...
setProfiles(profileData); // SETS HERE
};
useEffect(() => {
try {
const data = fetchProfiles();
} catch (error) {
console.log(error);
}
}, []);
Imagine profileData is constant mock data. And you can try this at
Stackblitz link

Fetch response gives JSON but needs to be `await` again, when used in a component

I am trying to write a common api service.
get.js is has 'get' api code. In get.js, I see response which is in json format. But when I call it in app.js, it's not received in json, I have to again await in order to use it? why?
// get.js
const getData = async (url) => {
try {
const response = await fetch(url);
const responseJson = await response.json();
console.log("responseJson: ", responseJson); // response is coming in json format
return responseJson; // returning that same `json`
} catch (error) {
console.log("Error: ", error);
}
return [];
};
export default getData;
responseJson is in json format, which is being returned.
// App.js
import "./styles.css";
import getData from "./get";
import { useEffect, useState } from "react";
export default function App() {
const [demoData, setDemoData] = useState([]);
useEffect(() => {
async function fetchData() {
const json = await getData("https://jsonplaceholder.typicode.com/users"); // why again I need to 'await'? rather than directly using the json.
// console.log("json: ", json);
setDemoData(json);
}
fetchData();
}, []);
return (
<div className="App">
{demoData.map((data) => {
console.log("data: ", data);
return <p>{data.name}</p>;
})}
</div>
);
}
I have to do await getData(), why is it like that?
CodeSandbox demo.
your getData function is an async one and you have to await in the app.js file because there are actions in getData that can take time and you don't get back result instantly.
So, in app.js file you have to await until all the process is finished inside getData and json response is sent back from there.
If you don't use await in app.js then, the code after the line ( where you are calling the getData method ) will be executed before you have received the response from the API.

React Native Axios return undefined from another file

i'm trying to fetch data from local with axios. But the fetch function is in another file. when i trying to print the response it returns undefined.
this is function file all_products.js
export default async function getAllProducts() {
await axios.get('http://10.0.2.2:3006/posts')
.then(response => {
const items = response.data;
return items;
})
.catch({});
}
and this is homepage where i trying to fetch data
constructor(props) {
super(props)
this.state = {
data: []
}
}
componentDidMount() {
getAllProducts().then((d) => this.setState({ data: d }))
}
here i'm trying to console log in render function
render() {
console.log("render : " + this.state.data)
...
and this is result
LOG render :
LOG render : undefined
The problem occurs because you don't return the promise from your axios call inside the function, that's why it returns undefined, nothing returns. The promise just resolves and that's it, you have to return the value from the function.
export default async function getAllProducts() {
return await axios.get('http://10.0.2.2:3006/posts') // <-- here
.then(response => {
const items = response.data;
return items;
})
.catch({});
}
also i'd suggest to rewrite this function to async await syntax, so you don't mix promises chaining and async await.
export default async function getAllProducts() {
const response = await axios.get('http://10.0.2.2:3006/posts')
const items = response.data
return items
}
if you want to catch errors, you can wrap it in trycatch block
export default async function getAllProducts() {
try {
const response = await axios.get('http://10.0.2.2:3006/posts')
const items = response.data
return items
} catch (err) {}
}

How to get response of a function in another file

I have two files named actions.js and vip.js. I have declared a function fetchVip in action file and imported it in vip file which will populate text element when screen is loaded. I want to access fetchVip response in vip file but i get undefined like this LOG useeffect undefined. While respone works as expected in action file.My code is below.
Vip File
import {fetchVip} from '../../Store/action';
const Vip = props => {
useEffect(() => {
console.log('useeffect', fetchVip());
}, [fetchVip()]);
action file
export const fetchVip = () => {
axios
.post(`${baseUrl}/get-vips`)
.then(function (response) {
return response.data;
})
.catch(function (error) {
console.log('error', error);
return {type: 'ERROR', payload: error};
});
};
fetchVip does not return anything, so you have to add a return statement here first:
export const fetchVip = () => {
return axios
.post(`${baseUrl}/get-vips`)
or remove the curly braces, then it will return as well.
export const fetchVip = () => axios
.post(`${baseUrl}/get-vips`)
...
return {type: 'ERROR', payload: error};
})
Now it will return a promise. That means that the result will not be there right away, but at some point later in time. Therefore, if you want to use it in the useEffect, you have to await for the result to arrive.
you could to this with the ES6 syntax:
useEffect(() => {
const getVip = async () => {
const vip = await fetchUsers();
console.log(vip)
//now you can do something with it
};
getVip();
}, [fetchVip]);
or the promise-then syntax:
useEffect(() => {
fetchVip().then(result => {
console.log(result);
//do something with the result
})
}, [fetchVip]);
This is wrong btw. remove the (). You want to check for the function here, not the result of the function.
}, [fetchVip()]);

Categories

Resources