I'm trying to map through data from an api, but i'm getting an error from Typescript. I've tried nesting Prop
types rather than them being siblings, and i've tried using empty values for the mvp
to see if I can find the issue. Here's my code:
Solution:
import { Key } from "react";
import Card from "../../components/Card/Card";
import SearchBar from "../../components/SearchBar/SearchBar";
import { HomeWrapper, CountryGrid } from "./Home.styled";
type Props = { data: any, };
type Grid = { region: string, };
function Home( {data}:Props ): JSX.Element {
return (
<HomeWrapper>
<SearchBar />
<CountryGrid>
{data.map((entry:Grid, index: Key | null | undefined) => {
return <Card key={index} image="" country="" region={entry.region} population="" capital="" />
})};
</CountryGrid>
</HomeWrapper>
)
}
export default Home
Issue
import Card from "../../components/Card/Card";
import SearchBar from "../../components/SearchBar/SearchBar";
import { HomeWrapper, CountryGrid } from "./Home.styled";
type Props = {
data: any,
index: string,
entry: {
image: string,
country: string,
region: string,
capital: string,
population: string,
name: { common: string, };
flags: { png: string, };
},
};
function Home( {data}:Props ): JSX.Element {
return (
<HomeWrapper>
<SearchBar />
<CountryGrid>
{data.map(({entry, index}:Props) => {
return (<Card key={index} image={entry.flags.png} country={entry.name.common} region={entry.region} population={entry.population} capital={entry.capital[0]} />)
})};
</CountryGrid>
</HomeWrapper>
)
}
export default Home
Edit: API Call
// make api call, assign response to data state.
// hasFetchedData ref ensures double rendering doesn't occur.
const [apiData, setApiData] = useState([]);
const hasFetchedData = useRef(false);
useEffect(() => {
async function fetchData() {
try {
await fetch('https://restcountries.com/v3.1/all')
.then(response => response.json())
.then(data => setApiData(data));
} catch (e) {
console.error('Error fetching api data', e);
};
};
if (hasFetchedData.current === false) {
fetchData();
hasFetchedData.current = true;
};
}, []);
CodePudding user response:
import { Key } from "react";
import Card from "../../components/Card/Card";
import SearchBar from "../../components/SearchBar/SearchBar";
import { HomeWrapper, CountryGrid } from "./Home.styled";
// split props
type Props = { data: any, };
type Grid = { region: string, };
function Home( {data}:Props ): JSX.Element {
return (
<HomeWrapper>
<SearchBar />
<CountryGrid>
{/* index has unique typescript type */}
{data.map((entry:Grid, index: Key | null | undefined) => {
return <Card key={index} image="" country="" region={entry.region} population="" capital="" />
})};
</CountryGrid>
</HomeWrapper>
)
}
export default Home
CodePudding user response:
First, declare a new type:
type Country = {
region: string,
capital: string[],
population: number,
name: { common: string, };
flags: { png: string, };
// ... other properties from the API object (no need to declare as you are not using them anywhere)
}
Here we are changing the type of props we are passing in the <Home />
component.
Change
function Home( {data}:Props ): JSX.Element
to
function Home( { data:Country[]} ): JSX.Element
The callback to the .map()
method accepts index
as second parameter. That is where we will get it from.
Change
data.map(({entry, index}:Props) =>
to
data.map((entry, index)) =>
Everything should work now.
You were basically saying to Typescript compiler that you were passing a Props
type to the <Home />
component, but that was not the case.
You were actually passing an array of API objects and above we declared that each object in that array is of type Country
CodePudding user response:
I have no prior experience with React but from the looks of it, it looks like you are defining data as the type Props and later on you want to map through Props (which you can't because it isn't an Array).
Try defining data at the Home function as Array like this: Home( {data}: Array<Props> ): JSX.Element