Home > Software engineering >  Error mapping through API data using Typescript
Error mapping through API data using Typescript

Time:05-17

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:

REST Countries API

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

  • Related