Custom hook for data fetching

By May 15, 2019javascript, react

This post is based on information on customer hooks and data fetching provided by others such as Robin Wieruch (https://www.robinwieruch.de/) and Kent Dodds (https://kentcdodds.com/blog/how-to-optimize-your-context-value).

This is a customer hook to fetch energy market data from the Australian Energy Market Operator (AEMO) website (http://data.wa.aemo.com.au/datafiles/balancing-summary/) . In this case Balance Market Summary data for 2019.

First, the following code is the custom hook. This hook:

  • uses state to
    • store the fetched data, and enable it to be set ([data, setData]);
    • store the url from where the data should be fetched, and enable it to be set ([url, setUrl]);
    • store a refresh state and allow it to be set, in order to trigger a refresh of the last fetched url data ([refresh, setRefresh]); and
    • store a loading state and allow it to be set([isLoading, setIsLoading]);
  • uses an effect to
    • perform the initial fetch and set the data in the data state;
    • manage setting and removing of the loading state; and
    • refetching the data (refresh) or fetching the data from a new url (url) if either of those states change.
  • has two helper functions
    • doRefresh, which forces a refetch of the last url loaded; and
    • doFetch, which forces a fetch from a new, passed-in, url.

The data, isLoading state, and helper functions doRefresh and doFetch, are exported as named exports and the overall hook useAemoData is exported as the default export.

// custom hook to handle fetching AEMO data from the ARMO website.

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

const useAemoData = () => {

    // AEMO data to be passeded into the app
    const [data, setData] = useState(null);

    // url to fetch.
    const [url, setUrl] = useState(

        'http://data.wa.aemo.com.au/datafiles/balancing-summary/balancing-summary-2019.csv'

    );

    // toggle to refresh the AEMO data
    const [refresh, setRefresh] = useState(0)

    // loading data state
    const [isLoading, setIsLoading] = useState(false);

    // useEffect to do an initial fetch on component mount and then
    // every time either the url changes or a refresh is requested.

    useEffect(() => {

        const fetchData = async () => {

            setIsLoading(true);

            try {

                const result = await axios(url);
                setData(result.data);

            } catch (err) {
                console.log(err);
            }

            setIsLoading(false)

        };

        fetchData();

    }, [url, refresh]);

    // refresh function which will refresh the last requested (or default) url

    const doRefresh = () => {
        setRefresh(refresh => refresh + 1);
    }

    // do a fetch with a passed in url
    const doFetch = (url) => {
        setUrl(url);
    }

   return { data, isLoading, doRefresh, doFetch };

}

export default useAemoData;

A simple way to use the hook is, for example, in a simple App.js component such as that below.

import React from 'react';
...
...
import useAemoData from './hooks/useAemoData';

const App = () => {

  let { data, isLoading, doRefresh } = useAemoData();

  return (
    {isLoading ? 
      <p> Loading ... </p> : 
      {data}
    }
  )