feat(catalog/swr): Added a nice stale-while-revalidate pattern for fetching data
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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<any> {
|
||||
@@ -79,11 +73,6 @@ export class CatalogClient implements CatalogApi {
|
||||
async getEntities(
|
||||
filter?: Record<string, string | string[]>,
|
||||
): Promise<Entity[]> {
|
||||
const cachedValue = this.cache.get<Entity[]>(
|
||||
`get:${JSON.stringify(filter)}`,
|
||||
);
|
||||
if (cachedValue) return cachedValue;
|
||||
|
||||
let path = `/entities`;
|
||||
if (filter) {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
@@ -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<{}> = () => {
|
||||
</div>
|
||||
<CatalogTable
|
||||
titlePreamble={selectedFilter.label}
|
||||
entities={value || []}
|
||||
loading={loading}
|
||||
entities={data || []}
|
||||
loading={!data && !error}
|
||||
error={error}
|
||||
actions={actions}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user