DEV Community

loading...
Cover image for How to fetch data from the network

How to fetch data from the network

rossanodan profile image Rossano D'Angelo ・3 min read

Introduction

In this article, I'm going to build the Home page of the application.
It will display the list of all the available seasons of the competition Serie A.

Setting up axios

To make HTTP calls I have two options: fetch or axios. For this article I choose to pick up axios

npm install axios
Enter fullscreen mode Exit fullscreen mode

Once installed, I create a new module, httpService.ts

import axios from 'axios';

const httpService = axios.create({
  baseURL: 'http://api.football-data.org',
  timeout: 1000,
  headers: {
    'X-Auth-Token': 'FOOTBALL DATA API KEY', // your account API Key
  },
});

export default httpService;
Enter fullscreen mode Exit fullscreen mode

This module exports an axios configuration that we can use throughout the application. Using this configuration I don't have to write every time same things like headers or the timeout of the request.

The Home component

In the first place, I'd like to take the Home component out from Routes.tsx.

import React, { Component } from 'react';

import {
  Container,
  Grid,
} from '@material-ui/core';

interface IProps {};

interface IState {
  matchday: number,
  matches: any[],
  competition: any,
  error: boolean,
  totalMatchdays: number,
};

class Home extends Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);
    this.state = {
      matchday: 1,
      matches: [],
      competition: null,
      error: false,
      totalMatchdays: 38,
    };
  }

  render() {
    return (
      <Container>
        Home
      </Container>
    );
  }
};
Enter fullscreen mode Exit fullscreen mode

Now, using httpService I can fetch data.

...
import httpService from '../../../services/httpService';
import { AxiosResponse } from 'axios';
...
fetch = () => {
  httpService
    .get(`/v2/competitions/2019/matches?matchday=${this.state.matchday}`)
    .then((response: AxiosResponse) => {
      this.setState({
        competition: response.data.competition,
        matches: response.data.matches,
      });
    })
    .catch((error: AxiosResponse) => {
      this.setState({ error: true });
    });
};
Enter fullscreen mode Exit fullscreen mode

This function has to be called everytime the state changes and the component is re-rendered: componentDidMount.

componentDidMount() {
  this.fetch();
};
Enter fullscreen mode Exit fullscreen mode

Adding some console.log I can see the response in the browser console

Alt Text

Now that I have the complete response, I can add more specific interfaces to my IState.

interface ICompetition {
  id: number;
  area: object;
  name: string;
  code: string;
  plan: string;
  lastUpdated: string;
};

interface IScore {
  winner: string;
  duration: string;
  fullTime: {
    homeTeam: number | null;
    awayTeam: number | null;
  };
  halfTime: {
    homeTeam: number | null;
    awayTeam: number | null;
  };
  extraTime: {
    homeTeam: number | null;
    awayTeam: number | null;
  };
  penalties: {
    homeTeam: number | null;
    awayTeam: number | null;
  };
};

interface ITeam {
  id: number;
  name: string;
};

interface IReferee {
  id: number;
  name: string;
  nationality: string | null;
};

interface IMatch {
  id: number;
  season: object;
  utcDate: string;
  status: 'SCHEDULED' | 'LIVE' | 'IN_PLAY' | 'PAUSED' | 'FINISHED' | 'POSTPONED' | 'SUSPENDED' | 'CANCELED';
  matchday: number;
  stage: string;
  group: string;
  lastUpdated: string;
  score: IScore;
  homeTeam: ITeam;
  awayTeam: ITeam;
  referees: IReferee[];
};

interface IState {
  matchday: number,
  matches: IMatch[] | [],
  competition: ICompetition | null,
  error: boolean,
  totalMatchdays: number,
};
Enter fullscreen mode Exit fullscreen mode

Displaying matches details

I can now access these information from the state

<ul>
  {matches.map((match: IMatch) => (
    <li key={match.id}>
      {match.homeTeam.name} <b>{match.score.fullTime.homeTeam}</b> - <b>{match.score.fullTime.awayTeam}</b> {match.awayTeam.name}
    </li>
  ))}
</ul>
Enter fullscreen mode Exit fullscreen mode

The list I obtain is the following.

Alt Text

For now, this component is limited because I can display only matches of the first matchday. But what if I want to choose the matchday I'd like to display?

Updating the list when state changes

I create a new function

handleChange = (event: any) => {
  this.setState({ matchday: event.target.value }, () => {
    this.fetch();
  });
};
Enter fullscreen mode Exit fullscreen mode

This handler fetches date from the APIs everytime is called.

Then, I add a new element in the UI: a select.

render() {
  const options = [];
  for (let index = 1; index <= this.state.totalMatchdays; index++) {
    options.push(<option key={index}>{index}</option>)
  }
...
  <select onChange={this.handleChange} value={this.state.matchday}>
    {options}
  </select>
Enter fullscreen mode Exit fullscreen mode

Everytime this select changes, the state is popoluated with new macthes of a different matchday.

Alt Text

Conclusion

Now that I added a basic functionality to the Home component, I can think how to improve it.

For example, the select can be replaced by the Material UI Select component https://material-ui.com/components/selects/; the ul can be improved by using Material UI Card component https://material-ui.com/components/cards/.

Discussion (0)

pic
Editor guide