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

React and Material UI (6 Part Series)

1) How to use Material UI in React 2) Building a navigation drawer with Material UI and React Router DOM 3 ... 4 3) Some reflections about React and TypeScript 4) How to fetch data from the network 5) Using Window.localStorage with React 6) How to use moment.js with React

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

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;

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>
    );
  }
};

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 });
    });
};

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

componentDidMount() {
  this.fetch();
};

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,
};

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>

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();
  });
};

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>

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/.

React and Material UI (6 Part Series)

1) How to use Material UI in React 2) Building a navigation drawer with Material UI and React Router DOM 3 ... 4 3) Some reflections about React and TypeScript 4) How to fetch data from the network 5) Using Window.localStorage with React 6) How to use moment.js with React

Posted on by:

rossanodan profile

Rossano D'Angelo

@rossanodan

Enthusiastic software engineer and tech lover, passionate about good music 🎶 and soccer ⚽️

Discussion

markdown guide