Home > other >  React JS Creating a reusable component to get API Data
React JS Creating a reusable component to get API Data

Time:11-26

I'm trying to create a component that allows me to access API data anywhere I import it.

I have a GetTeamsByLeague component which looks like this.

import axios from 'axios';

const GetTeamsByLeague = (league: string) => {
    const teams = axios
        .get(`http://awaydays-api.cb/api/teams/${league}`)
        .then((response: any) => {
            return response;
        })
        .catch((error: any) => {
            console.log(error);
        });

    return teams;
};

export default GetTeamsByLeague;

Then in my app component, I have this

import Header from './Components/Header/Header';
import GetTeamsByLeague from './Hooks/GetTeamsByLeague';

import './Reset.scss';

function App() {
    const championshipTeams = GetTeamsByLeague('Championship');
    console.log(championshipTeams);
    return (
        <div className='App'>
            <Header/>
        </div>
    );
}

export default App;

The issue is the console.log() just return the promise not the data.

If I use useState() in my GetTeamsByLeague component like this

import axios from 'axios';
import { useState } from 'react';

const GetTeamsByLeague = (league: string) => {
    const [teams, setTeams] = useState({});

    axios
        .get(`http://awaydays-api.cb/api/teams/${league}`)
        .then((response: any) => {
            setTeams(response.data);
        })
        .catch((error: any) => {
            console.log(error);
        });
    return teams;
};

export default GetTeamsByLeague;

Then I get the following errors

(3) [{…}, {…}, {…}] ...

GET http://awaydays-api.cb/api/teams/Championship 429 (Too Many Requests)

/* EDIT */

I've now updated my GetTeamsByLeague component too

import axios from 'axios';
import { useEffect, useState } from 'react';

interface Teams {
    id: number;
    name: string;
    league: string;
    created_at: string;
    updated_at: string;
}

const useGetTeamsByLeague = (league: string) => {
    const [teams, setTeams] = useState<Teams[]>();

    useEffect(() => {
        axios
            .get(`http://awaydays-api.cb/api/teams/${league}`)
            .then((response: any) => {
                setTeams(response.data);
            })
            .catch((error: any) => {
                console.log(error);
            });
    }, [league, setTeams]);

    return teams;
};

export default useGetTeamsByLeague;

In my component done

import useGetTeamsByLeague from './Hooks/useGetTeamsByLeague';

import './Reset.scss';

function App() {
    const teams = useGetTeamsByLeague('Championship');
    console.log(useGetTeamsByLeague);
    return (
        <div className='App'>
            <Header>
                {teams.map(team => {
                    <li>{team.name}</li>;
                })}
            </Header>
        </div>
    );
}

export default App;

But now I get TypeScript error Object is possibly 'undefined' The console.log shows empty array first then the data

undefined

(3) [{…}, {…}, {…}]

CodePudding user response:

In the first case, you return a Promise since you don't await the axios fetch. In the second case, after the axios fetch succeeds, you store the result in the state which re-renders the component, which causes an infinite loop of fetching -> setting state -> re-rendering -> fetching [...].

This is a perfect use case for a React hook. You could do something like this:

const useGetTeamsByLanguage = (language) => {
    const [status, setStatus] = useState('idle');
    const [teams, setTeams] = useState([]);

    useEffect(() => {
        if (!language) return;

        const fetchData = async () => {
            setStatus('fetching');
            const {data} = await axios.get(
                `http://awaydays-api.cb/api/teams/${league}`);
            if(data){
               setTeams(data);
             }
            setStatus('fetched');
        };

        fetchData();
    }, [language]);

    return { status, teams };
};

And then inside your components do

const {status, teams} = useGetTeamsByLanguage("someLanguage");

Ofc. you should modify the hook to your needs since I don't know how your data structure etc. looks like.

CodePudding user response:

A component function is run on every render cycle, therefore the request is many times. You should use the useEffect() hook (documentation).

Wrapping this logic in a component is probably not the right tool to use in this case. You should probably consider a custom hook instead, for example:

const useGetTeamsByLeague = (league: string) => {
    const [teams, setTeams] = useState({});

    useEffect(() => {
        axios
            .get(`http://awaydays-api.cb/api/teams/${league}`)
            .then((response: any) => {
                setTeams(response.data);
            })
            .catch((error: any) => {
                console.log(error);
            });
    }, [league, setTeams]);

    return teams;
};
  • Related