Source

src/hooks/useGetTable.js

import { useEffect, useMemo } from "react";
import { useDispatch, useSelector } from "react-redux";
import { wrap } from "comlink";
import { dataSelectors, dataActions } from '../stores/dataStore'
const { selectStoredDatasets } = dataSelectors;
const { reconcileTable } = dataActions;

const FetcherWorker =  wrap(new Worker(new URL('../workers/fetcher', import.meta.url)));

/**
 * Hook to fetch data from a remote source, or return it from the local data store, if it exists.
 * 
 * @category Hooks
 * @param {Object} props
 * @param {FileInfo[]} props.filesToFetch List of files to fetch
 * @param {boolean} props.shouldFetch Flag to indicate if should fetch data 
 * @returns {Array} Positional data of [returnData: Dataset, dataReady: boolean, error: boolean | string]. For more on Dataset, see {@link /src/stores/dataStore/types.ts}
 */
function useGetTable({
  filesToFetch = [],
  shouldFetch = false,
  dateLists = {},
}) {
  const dispatch = useDispatch();  
  const fileSchemaNames = filesToFetch.map((fileSchema) => fileSchema.name)
  const accessedData = useSelector(selectStoredDatasets(fileSchemaNames))
  
  useEffect(() => {    
    if (shouldFetch) {
      if (filesToFetch[0] && !filesToFetch[0].noFile) {
        const cleanedFilesToFetch = filesToFetch.filter((fileSchema, idx) => {
          const fileExists = !!accessedData[idx];
          const fileExistsAndIsLoaded =
            fileExists &&
            !!accessedData[idx]?.loaded?.includes(fileSchema?.timespan);
          return !fileExists || !fileExistsAndIsLoaded;
        });
        const getData = async () => FetcherWorker.fetch(cleanedFilesToFetch, dateLists)
        getData()
          .then((dataArray) => {
            if (dataArray.length) {
              dataArray.forEach(({ value: newData }, idx) => {
                dispatch(reconcileTable({
                    name: cleanedFilesToFetch[idx].name,
                    newData,
                    timespan: cleanedFilesToFetch[idx].timespan,
                  }))
              });
            }
          })
          .catch((e) => console.log("error fetching table!", e, cleanedFilesToFetch));
      }
    }
  }, [shouldFetch, JSON.stringify(filesToFetch)]);

  const { dataReady, returnData, error } = useMemo(() => {
    const dataReady =
      filesToFetch.length &&
      filesToFetch.every(({ name, timespan }, idx) => {
        const missingParams = !name || !timespan;
        const temporalDataLoaded = accessedData[idx] && accessedData[idx]?.loaded?.includes(timespan) 
        const xSectionDataLoaded = accessedData[idx] && accessedData[idx]?.columns?.length > 0;
        const fileIsNull = filesToFetch.every(({noFile}) => noFile);
        return temporalDataLoaded || xSectionDataLoaded || fileIsNull || missingParams;
      });
    const returnData = dataReady ? accessedData[0] : undefined;
    const error = false;
    return {
      returnData,
      dataReady,
      error,
    };
  }, [JSON.stringify(accessedData[0]?.loaded), JSON.stringify(filesToFetch)]);
  
  return [returnData, dataReady, error]; //currentLoadedTables
}

export default useGetTable;