Skip to content

Commit

Permalink
refactor(frontend): refactor data load triggers (#159)
Browse files Browse the repository at this point in the history
Remove some of the complexity from the data load triggers for the data map, without breaking the Adaptions map. These triggers rerender the data map whenever we make a change to the adaptation options sidebar panel.
  • Loading branch information
eatyourgreens authored Oct 14, 2024
1 parent df3e1fe commit e000f43
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 33 deletions.
21 changes: 6 additions & 15 deletions frontend/src/lib/data-map/DataMap.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import type { MapboxOverlay } from '@deck.gl/mapbox/typed';
import { useMap } from 'react-map-gl/maplibre';
import { FC, useMemo, useRef } from 'react';
import { FC, useRef } from 'react';

import { useInteractions } from 'lib/state/interactions/use-interactions';
import { useTriggerMemo } from 'lib/hooks/use-trigger-memo';
import { useDataLoadTrigger } from 'lib/data-map/use-data-load-trigger';
import { InteractionGroupConfig } from 'lib/data-map/types';
import { DeckGLOverlay } from 'lib/map/DeckGLOverlay';
Expand Down Expand Up @@ -40,13 +39,9 @@ function buildLayers(
}

function useTrigger(viewLayers: ViewLayer[]) {
const dataLoaders = useMemo(
() =>
viewLayers
.map((vl) => vl.dataAccessFn?.(vl.styleParams?.colorMap?.fieldSpec)?.dataLoader)
.filter(Boolean),
[viewLayers],
);
const dataLoaders = viewLayers
.map((vl) => vl.dataAccessFn?.(vl.styleParams?.colorMap?.fieldSpec)?.dataLoader)
.filter(Boolean);

return useDataLoadTrigger(dataLoaders);
}
Expand All @@ -61,19 +56,15 @@ export const DataMap: FC<{
const { current: map } = useMap();
const zoom = map.getMap().getZoom();

const dataLoadTrigger = useTrigger(viewLayers);
useTrigger(viewLayers);

const { onHover, onClick, layerFilter, pickingRadius } = useInteractions(
viewLayers,
lookupViewForDeck,
interactionGroups,
);

const layers = useTriggerMemo(
() => buildLayers(viewLayers, viewLayersParams, zoom, firstLabelId),
[viewLayers, viewLayersParams, zoom, firstLabelId],
dataLoadTrigger,
);
const layers = buildLayers(viewLayers, viewLayersParams, zoom, firstLabelId);

return (
<DeckGLOverlay
Expand Down
37 changes: 19 additions & 18 deletions frontend/src/lib/data-map/use-data-load-trigger.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,47 @@
import difference from 'lodash/difference';
import { useEffect } from 'react';
import { useEffect, useState } from 'react';

import { DataLoader } from '../data-loader/data-loader';
import { usePrevious } from '../hooks/use-previous';
import { useTrackingRef } from '../hooks/use-tracking-ref';
import { useTrigger } from '../hooks/use-trigger';

const DEFAULT_LOADERS: DataLoader[] = [];

/**
* Based on a list of data loaders extracted from view layers,
* returns a number which can be used as a trigger to recalculate a list of deck layers.
*
*/
export function useDataLoadTrigger(dataLoaders: DataLoader<any>[]) {
const [dataLoadTrigger, doTriggerDataUpdate] = useTrigger();

const previousLoaders = usePrevious(dataLoaders);
export function useDataLoadTrigger(dataLoaders: DataLoader[]) {
const [trigger, setTrigger] = useState(0);
const previousLoaders = usePrevious(dataLoaders) ?? DEFAULT_LOADERS;
const removedLoaders = difference(previousLoaders, dataLoaders);
const addedLoaders = difference(dataLoaders, previousLoaders);

useEffect(() => {
function incrementTrigger() {
setTrigger((trigger) => trigger + 1);
}
// destroy removed data loaders to free up memory
const removedLoaders = difference(previousLoaders ?? [], dataLoaders);
removedLoaders.forEach((dl) => dl.destroy());

// subscribe to new data loaders to get notified when data is loaded
const addedLoaders = difference(dataLoaders, previousLoaders ?? []);
addedLoaders.forEach((dl) => dl.subscribe(doTriggerDataUpdate));
// subscribe to new data loaders to trigger an update to the data map when data is loaded
addedLoaders.forEach((dl) => dl.subscribe(incrementTrigger));

// if there was a change in data loaders, trigger an update to the data map
if (addedLoaders.length > 0 || removedLoaders.length > 0) {
doTriggerDataUpdate();
incrementTrigger();
}
}, [dataLoaders, previousLoaders, doTriggerDataUpdate]);
}, [addedLoaders, removedLoaders]);

/* store current value of dataLoaders so that we can clean up data on component unmount
* this is necessary because we don't want to keep the data loaders around after the component is unmounted
*/
const currentLoadersRef = useTrackingRef(dataLoaders);
useEffect(() => {
return () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
currentLoadersRef.current?.forEach((dl) => dl.destroy());
previousLoaders?.forEach((dl) => dl.destroy());
};
}, [currentLoadersRef]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return dataLoadTrigger;
return trigger;
}

0 comments on commit e000f43

Please sign in to comment.