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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.