I am getting the response and storing that into the array but I am unable to destructure the data from that array,How do i log title of every product inside the div ?
import React, { useEffect, useState } from "react";
import axios from "axios";
const ProductsAPI = () => {
const [item, setItem] = useState([]);
useEffect(() => {
axios
.get("https://fakestoreapi.com/products")
.then((res) => setItem(res.data));
}, []);
return <div></div>;
};
export default ProductsAPI;
You can map over the state value inside your render
<div>
<ul>
{item.map((item,index) =><li key={index}>
{item.title}
</li>) }
</ul>
</div>
You need to loop through your res.data by mapping inside of your render().
useEffect(() => {
axios.get(`https://fakestoreapi.com/products`)
.then(res => {
const yourSavedData = res.data;
this.setState({yourSavedData });
})
}
render() {
return (
<div>
{
this.state.yourSavedData
.map(someName => // <-- Your Callback
<div data-something={yourSavedData.whatever_key}>{yourSavedData.another_key}</div><br />
)
}
</div>
)
}
Related
I need help (Api calls in React Js Hooks) Why is this nort working?
I need to call the values from that API
import React, { useEffect, useState } from 'react';
function Customers() {
const [customers, setCustomers] = useState(null);
useEffect(() => {
fetch('https://reactstarter-app.herokuapp.com/api/customers') **API CALLS**
.then(res => res.json())
.then(customers => setCustomers(customers))
}, [])
return (
<div>
<h2>Customers</h2>
<ul>
{customers.map((customer) => {
return <li key={customer.id}>{customer.firstName} {customer.lastName}</li>
})}
</ul>
</div>
);
}
export default Customers;
Maybe it isn't a solution, but I cannot paste code to comment, so I have to post an answer:
function Customers() {
// this is where you declare the "customers" const
const [customers, setCustomers] = useState(null);
useEffect(() => {
fetch('https://reactstarter-app.herokuapp.com/api/customers') **API CALLS**
.then(res => res.json())
// this is where you should change the "customers" to "data"
// because of the variable name conflict
.then(data => setCustomers(data))
}, [])
It looks like you're trying to map through a null state and probably getting an error, use conditional rendering to avoid the error and render the customers after the api request:
import React, { useEffect, useState } from 'react';
function Customers() {
const [customers, setCustomers] = useState(null);
useEffect(() => {
fetch('https://reactstarter-app.herokuapp.com/api/customers') **API CALLS**
.then(res => res.json())
.then(customers => setCustomers(customers))
}, [])
return (
<div>
<h2>Customers</h2>
{!customers ? <h2>Loading customers...</h2> :
<ul>
{customers.map((customer) => {
return <li key={customer.id}>{customer.firstName} {customer.lastName}</li>
})}
</ul>}
</div>
);
}
export default Customers;
import React, { useState, useEffect, } from "react";
function ProductDetail({match}) {
useEffect(() => {
fetchItem();
// console.log(match)
}, );
const fetchItem = async () => {
const fetchItem = await fetch(`https://fortnite-api.theapinetwork.com/item/get?id={{itemid}}`);
const item = await fetchItem.json();
console.log(item);
}
return (
<div className="containter productsDetails">
<h1>Product Detail</h1>
</div>
);
}
export default ProductDetail;
enter image description here
import React, { useState, useEffect } from "react";
import {Link} from "react-router-dom";
function Products() {
const [data, setData] = useState([]);
const apiGet = () => {
fetch(`https://fortnite-api.theapinetwork.com/items/popular`)
.then((response) => response.json())
.then((json) => {
console.log(json);
setData(json);
});
};
useEffect(() => {
apiGet();
},[])
return (
<div>
<div>
<ul>
{data.map(item =>
<li key={item.id}>
<Link to={`/products/${item.id}`}>{item.item}</Link>
</li>
)}
</ul>
</div>
</div>
);
}
export default Products;
I have tried every way I can find online.
I am unable to map into the entries object of this API. I would like to map to the 3 array objects.
So that I can {match} using an ID when I click one of them.
The routing is working. But I can not display any of the data on the screen. In Console it is displaying.
He is the API fortnite-api.theapinetwork.com/items/popular
You're trying to use map function on object. map only works for arrays.
Here's the link to sandbox how it should be
I have a simple list in React where I'm fetching data from an array, and it's working.
But now that I want to fetch data from an external API, I have the following error
Cannot read property 'map' of undefined
I tried replacing .data with .json() but didn't work.
https://codesandbox.io/s/silly-taussig-e3vy7?file=/src/App.js:561-571
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
import axios from "axios";
export default () => {
const initialList = [
{
id: "1",
name: "John"
},
{
id: "2",
name: "Doe"
},
{
id: "3",
name: "Seb"
}
];
const [list, setList] = React.useState([]);
const [name, setName] = React.useState("");
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users/")
.then((response) => {
setList(response.data.list);
})
.catch((err) => console.log(err));
}, []);
function handleChange(event) {
setName(event.target.value);
}
function handleAdd() {
const newList = list.concat({ name });
setList(newList);
setName("");
}
return (
<div>
<div>
<input type="text" value={name} onChange={handleChange} />
<button type="button" onClick={handleAdd}>
Add
</button>{" "}
</div>
<ul>
<div>
{list.map((item, index) => (
<li key={item.id}>
<div>{item.name}</div>
</li>
))}
</div>
</ul>
</div>
);
};
The result of your API doesn't have data.list
Try instead:
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users/")
.then((response) => {
setList(Object.values(response.data));
})
.catch((err) => console.log(err));
}, []);
Issue is with the way you are processing the response from the XHR call. The data returned by the URL https://jsonplaceholder.typicode.com/users/ is an array. There is no element called list in the data. So when you do response.data.list, the list variable gets set to undefined.
PFB revised code
https://codesandbox.io/s/hungry-tdd-xjw6z
...
axios
.get("https://jsonplaceholder.typicode.com/users/")
.then((response) => {
setList(response.data); //Change here
})
.catch((err) => console.log(err));
}, []);
...
I am trying to render a component that call an api with the prop that i am passing, but i have this error: Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
And other that say that it cannot read the property map of null, this is my code
import React, { useEffect } from "react";
const GetLeagues = async (country) => {
const url = `https://www.thesportsdb.com/api/v1/json/1/search_all_leagues.php?c=${country}&s=Soccer`;
const res = await fetch(url);
const { countrys } = await res.json();
return (
<div>
<ul>
{countrys.map((country, i) => {
return <li key={i}>{country.strLeague}</li>;
})}
</ul>
</div>
);
};
const Leagues = () => {
useEffect(() => {
GetLeagues();
}, []);
return (
<div>
<GetLeagues country={"Spain"} />
</div>
);
};
export default Leagues;
You shouldn't make side effects in the component body, you should use useEffect to make side effects, hence you shouldn't make your components async but instead, you can define your functions as async, use them in useEffect and then set your state.
function Leagues({ country }) {
const [countryData, setCountryData] = React.useState([]);
React.useEffect(() => {
async function getCountries() {
const url = `https://www.thesportsdb.com/api/v1/json/1/search_all_leagues.php?c=${country}&s=Soccer`;
const res = await fetch(url);
const { countrys } = await res.json();
setCountryData(countrys);
}
getCountries();
}, [country]);
return (
<div>
<ul>
{countryData.map((country, i) => {
return <li key={i}>{country.strLeague}</li>;
})}
</ul>
</div>
);
}
ReactDOM.render(
<Leagues country="Spain" />,
document.getelementById("root")
);
Since async functions is not supported in the snippet, here is a working version with .then promise chaining.
function Leagues({ country }) {
const [countryData, setCountryData] = React.useState([]);
React.useEffect(() => {
const url = `https://www.thesportsdb.com/api/v1/json/1/search_all_leagues.php?c=${country}&s=Soccer`;
fetch(url)
.then((res) => res.json())
.then(({ countrys }) => setCountryData(countrys));
}, [country]);
return (
<div>
<ul>
{countryData.map((country, i) => {
return <li key={i}>{country.strLeague}</li>;
})}
</ul>
</div>
);
}
ReactDOM.render(
<Leagues country="Spain" />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root" />
Here is the component, just call it in App with <Leagues c='Spain'/>
I call the parameter c because country was clearly not readable having countrys everywhere.
import React, { useEffect, useState } from "react";
const Leagues = ({c}) => {
const [countrys, countrysSet] = useState(false);
useEffect(() => {
countrysSet(false);
const url = `https://www.thesportsdb.com/api/v1/json/1/search_all_leagues.php?c=${c}&s=Soccer`;
fetch(url).then( res => res.json()).then(countrysSet);
}, [c]);
if( countrys === false ) {
return <p>loading...</p>;
}
return (
<div>
<ul>
{countrys.map((country, i) => {
return <li key={i}>{country.strLeague}</li>;
})}
</ul>
</div>
);
};
export default Leagues;
I think you should break that code down in a few parts. Also, you cannot make api calls in the body of your function, else it will run every time your component is re rendered. Let me show you using your example:
import React, { useEffect, useState } from "react";
const GetLeagues = async (country) => {
// This helper function fetches your leagues
const url = 'your url'
const res = await fetch(url);
const { countries } = await res.json();
return countries;
};
const Leagues = () => {
const [leagues, setLeagues] = useState([]);
useEffect(() => {
async function init() {
// Declaring an extra function as useEffect
// cannot be async.
const countries = await GetLeagues();
setLeagues(countries);
}
init();
}, []);
return (
<div>
{leagues.map((country, i) => {
return <li key={i}>{country.strLeague}</li>;
})}
</div>
);
};
export default Leagues;
Note that now "GetLeagues" is just an utilitary function, not a React component. So that could be reused without rendering anything.
Also, your "Leagues" component handles all the necessary operations to render itself.
Im having troubles rendering components based on api calls in React. I fetch my data in useEffect hook update a state with the data. The state is null for a while before the api get all the data but by that time, the components are rendering with null values. This is what I have:
import React, { useEffect, useState } from 'react'
import axios from 'axios';
import { Redirect } from 'react-router-dom';
const Poll = (props) => {
const [poll, setPoll] = useState(null);
//if found is 0 not loaded, 1 is found, 2 is not found err
const [found, setFound] = useState(0);
useEffect(() => {
axios.get(`api/poll/${props.match.params.id}`)
.then(res => {
console.log(res.data);
setPoll(res.data);
setFound(1);
})
.catch(err => {
console.log(err.message);
setFound(2);
});
}, [])
if(found===2) {
return(
<Redirect to="/" push />
)
}else{
console.log(poll)
return (
<div>
</div>
)
}
}
export default Poll
That is my workaround but it doesnt feel like thats the way it should be done. How can I set it so that I wait for my api data to get back then render components accordingly?
You don't need to track the state of the API call like const [found, setFound] = useState(1). Just check if poll exists and also you can create a new state variable for tracking the error.
For example if (!poll) { return <div>Loading...</div>} this will render a div with 'loading...' when there is no data. See the code below, for complete solution,
import React, { useEffect, useState } from 'react'
import axios from 'axios';
import { Redirect } from 'react-router-dom';
const Poll = (props) => {
const [poll, setPoll] = useState(null);
const [hasError, setHasError] = useState(false);
useEffect(() => {
axios.get(`api/poll/${props.match.params.id}`)
.then(res => {
console.log(res.data);
setPoll(res.data);
})
.catch(err => {
console.log(err.message);
setHasError(true)
});
}, [])
if(!poll) {
console.log('data is still loading')
return(
<div>Loading....</div>
)
}
if (hasError) {
console.log('error when fetching data');
return (
<Redirect to="/" push />
)
}
return (
<div>
{
poll && <div>/* The JSX you want to display for the poll*/</div>
}
</div>
);
}
export default Poll
In your than, try to use a filter:
setPoll(poll.filter(poll => poll.id !== id));
Make sure to replace id by your identificator
The standard way is to have other variables for the loading and error states like this
const Poll = (props) => {
const [poll, setPoll] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
useEffect(() => {
setLoading(true);
axios.get(`api/poll/${props.match.params.id}`)
.then(res => {
console.log(res.data);
setPoll(res.data);
})
.catch(err => {
console.log(err.message);
setError(true);
})
.finally(()=> {
setLoading(false);
};
}, [])
if(error) return <span>error<span/>
if(loading) return <span>loading<span/>
return (
<div>
// your poll data
</div>
)
}