Skip to Content

Last Updated: 4/6/2026


Fetching Data in Components

This guide explains how to fetch GeoJSON and JSON data files in Vue components for the “Where Did They Go?” application. The project uses custom composable functions that provide reactive data loading with automatic retry logic and loading states.

The Fetch Composables

The application provides two composable functions in client/src/utility/fetchers.js:

  • fetchGeojson(pathString) — Fetches and parses GeoJSON files
  • fetchJson(pathString) — Fetches and parses JSON files

Both functions return the same result object structure:

{ result: { data, // ref: parsed data or null loading, // ref: true while fetching, false when complete error // ref: error object if fetch fails, otherwise null }, promise, // Promise from the initial fetch refresh // function: re-fetch the data }

Basic Usage in a Component

Here’s how to fetch GeoJSON data when a component mounts:

import { onMounted, watch } from 'vue'; import { fetchGeojson } from '../utility/fetchers'; onMounted(() => { const { result } = fetchGeojson('/kansas/geojson/railroads.geojson'); renderToSVG(result); }); function renderToSVG(r) { let d = r.data.value; let l = r.loading.value; let e = r.error.value; if (l) { // Data is still loading - watch for completion const unwatch = watch( () => r.loading.value, () => { renderToSVG(r); unwatch(); } ); return; } else if (e) { // Handle error console.error(e); return; } // Use the loaded data // d.features contains the GeoJSON features array }

Automatic Retry Logic

Both fetch composables include built-in retry logic. If a fetch fails, the function automatically retries up to 3 times (configurable via the maxRetries parameter in the internal fetchWrapper function). Only after all retries fail will the error ref be populated.

This retry mechanism helps handle transient network issues without requiring manual error recovery code in every component.

Using FetchQueue for Sequential Loading

For components that need to fetch data in a specific order or manage multiple concurrent fetches, use the FetchQueue class from client/src/utility/FetchQueue.js:

import { FetchQueue } from '../utility/FetchQueue'; const queue = new FetchQueue(); // Enqueue multiple fetches const { result, promise } = fetchGeojson('/kansas/geojson/KSCounty_1860_GeoJSON.geojson'); queue.enqueue(promise, result, renderToSVG);

The FetchQueue enforces first-in-first-out (FIFO) resolution order. Each callback receives the result object once the previous promise resolves. The queue automatically resets after 50 enqueued promises (configurable via the constructor’s max parameter).

Data File Locations

The Express backend serves static files from server/public/ via the express.static() middleware configured in server/app.js. All data files accessible to the frontend are located within this directory:

  • GeoJSON files: server/public/kansas/geojson/ — County borders, cities, railroads, water features, healthcare facilities, schools
  • JSON data files: server/public/kansas/json/ — Population data and other tabular datasets

Note: The server/data/ directory exists in the repository but is NOT served by Express and is not accessible via HTTP requests from the frontend.

All paths in fetchGeojson() and fetchJson() are relative to the server root (server/public/).

Example: Fetching County Borders

The BorderData.vue component demonstrates fetching GeoJSON with a queue:

import { fetchGeojson } from '../utility/fetchers'; import { FetchQueue } from '../utility/FetchQueue'; const queue = new FetchQueue(); onMounted(() => { let { result, promise } = fetchGeojson( '/kansas/geojson/KSCounty_1860_GeoJSON.geojson' ); queue.enqueue(promise, result, renderToSVG); }); // Later, when the year changes: hooks.onYearChange((newValue) => { let { result, promise } = fetchGeojson( `/kansas/geojson/KSCounty_${newValue}_GeoJSON.geojson` ); queue.enqueue(promise, result, renderToSVG); });

Rendering GeoJSON to SVG

Once data loads, use D3’s geoPath generator to convert GeoJSON features into SVG path elements:

import * as d3 from 'd3'; const pathGen = d3.geoPath(props.properties.projection); function renderToSVG(r) { let d = r.data.value; // ... check loading and error states ... selection = gTag .selectAll('.rail') .data(d.features) .join( (enter) => enter .append('path') .attr('d', pathGen) .classed('rail', true), (update) => update, (exit) => exit.remove() ); }

The pathGen function expects GeoJSON Feature objects and returns SVG path data strings.

What’s Next