From 1a581d4d260e6ddac9acaebd88a7cdfcfa9a2736 Mon Sep 17 00:00:00 2001 From: blam Date: Fri, 12 Jun 2020 00:29:42 +0200 Subject: [PATCH] feat(catalog/swr): Added a nice stale-while-revalidate pattern for fetching data --- plugins/catalog/package.json | 4 +-- plugins/catalog/src/api/CatalogClient.ts | 11 ------- .../components/CatalogPage/CatalogPage.tsx | 31 +++++++++++++------ 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 106f6c713a..c6457aa8a8 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -30,12 +30,12 @@ "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", - "node-cache": "^5.1.1", "react": "^16.13.1", "react-dom": "^16.13.1", "react-router": "^5.2.0", "react-router-dom": "^5.2.0", - "react-use": "^14.2.0" + "react-use": "^14.2.0", + "swr": "^0.2.2" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.7", diff --git a/plugins/catalog/src/api/CatalogClient.ts b/plugins/catalog/src/api/CatalogClient.ts index d8add18f68..3804315ace 100644 --- a/plugins/catalog/src/api/CatalogClient.ts +++ b/plugins/catalog/src/api/CatalogClient.ts @@ -19,14 +19,9 @@ import { Location, LOCATION_ANNOTATION, } from '@backstage/catalog-model'; -import Cache from 'node-cache'; import { CatalogApi, EntityCompoundName } from './types'; export class CatalogClient implements CatalogApi { - // TODO(blam): This cache is just temporary until we have GraphQL. - // And client side caching using things like React Apollo or Relay. - // There's a lot of loading states that cause flickering around the app which aren't needed. - private cache: Cache; private apiOrigin: string; private basePath: string; @@ -39,7 +34,6 @@ export class CatalogClient implements CatalogApi { }) { this.apiOrigin = apiOrigin; this.basePath = basePath; - this.cache = new Cache({ stdTTL: 10 }); } private async getRequired(path: string): Promise { @@ -79,11 +73,6 @@ export class CatalogClient implements CatalogApi { async getEntities( filter?: Record, ): Promise { - const cachedValue = this.cache.get( - `get:${JSON.stringify(filter)}`, - ); - if (cachedValue) return cachedValue; - let path = `/entities`; if (filter) { const params = new URLSearchParams(); diff --git a/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx index 570648f26b..50f8622aff 100644 --- a/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx @@ -33,9 +33,8 @@ import Edit from '@material-ui/icons/Edit'; import GitHub from '@material-ui/icons/GitHub'; import Star from '@material-ui/icons/Star'; import StarOutline from '@material-ui/icons/StarBorder'; -import React, { FC, useCallback, useState } from 'react'; +import React, { FC, useCallback, useState, useEffect } from 'react'; import { Link as RouterLink } from 'react-router-dom'; -import { useAsync } from 'react-use'; import { catalogApiRef } from '../..'; import { defaultFilter, entityFilters, filterGroups } from '../../data/filters'; import { findLocationForEntityMeta } from '../../data/utils'; @@ -45,6 +44,7 @@ import { CatalogFilterItem, } from '../CatalogFilter/CatalogFilter'; import { CatalogTable } from '../CatalogTable/CatalogTable'; +import useStaleWhileRevalidate from 'swr'; const useStyles = makeStyles(theme => ({ contentWrapper: { @@ -70,11 +70,24 @@ export const CatalogPage: FC<{}> = () => { defaultFilter, ); - const { value, error, loading } = useAsync(async () => { - const filter = entityFilters[selectedFilter.id]; - const all = await catalogApi.getEntities(); - return all.filter(e => filter(e, { isStarred: isStarredEntity(e) })); - }, [selectedFilter.id, starredEntities.size]); + const { data: entities, error, revalidate } = useStaleWhileRevalidate( + ['catalog', entityFilters[selectedFilter.id]], + async (_, filter) => { + return await catalogApi.getEntities(); + }, + { compare: () => false }, + ); + + const data = + entities?.filter(e => + entityFilters[selectedFilter.id](e, { isStarred: isStarredEntity(e) }), + ) ?? []; + + const revalidator = starredEntities.size || {}; + + useEffect(() => { + revalidate(); + }, [revalidate, revalidator]); const onFilterSelected = useCallback( selected => setSelectedFilter(selected), @@ -195,8 +208,8 @@ export const CatalogPage: FC<{}> = () => {