Skip to content

Commit 2f82194

Browse files
Implemented LRU Cache - Removing the least recently used resource (#87)
1 parent f927138 commit 2f82194

File tree

29 files changed

+501
-76
lines changed

29 files changed

+501
-76
lines changed

docs/resources/creation.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ export const userProfileResource = createResource({
2020
| `getKey` | `(routerContext, customContext) => string` | The return value of this function is used to identify this resource within the `type` namespace. The function itself is supplied with `routerContext` and `customContext` so that the composition of keys can use this data if required |
2121
| `getData` | `(routerExtendedContext, customContext) => Promise<any>` | This function is used to load the data for the resource. The function should return a promise and resolve with the resource data object. NOTE: You may not use `getData` and `getDataLoader` on the same resource |
2222
| `maxAge` | `number` | How long (in milliseconds) the resource should be kept in the router before a fresh resource is retrieved. Note: resources are only refreshed on route _change_. The router does not poll or update resources in the background. Navigation within the same route, e.g. query param change, will not trigger a refresh of resources. |
23-
| `getDataLoader` | `() => Promise<{default: getData}>` | Optional property that enables neater code splitting. See more below. NOTE: You may not use `getData` and `getDataLoader` on the same resource |
23+
| `maxCache` | `number` | How many resources can be kept in the router for a particular `type`. Once the threshold limit is reached, a **Least Recently** used resource gets deleted, making space for the new requested resource of the same type. |
24+
| `getDataLoader` | `() => Promise<{default: getData}>` | Optional property that enables neater code splitting. See more below. NOTE: You may not use `getData` and `getDataLoader` on the same resource |

examples/routing-with-resources/about.tsx

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,39 @@
11
import React from 'react';
2-
import { Link, createResource, useResource } from 'react-resource-router';
2+
import {
3+
Link,
4+
createResource,
5+
useResource,
6+
useQueryParam,
7+
} from 'react-resource-router';
38
import { homeRoute } from './routes';
49

510
export const aboutResource = createResource({
611
type: 'about',
7-
getKey: () => 'data',
8-
maxAge: 0,
9-
getData: async () => {
12+
getKey: ({ query }) => `${query.name}`,
13+
maxAge: 30000,
14+
getData: async ({ query }) => {
15+
const { name } = query;
1016
const response = await fetch(
11-
'https://dog.ceo/api/breed/schnauzer/images/random'
17+
`https://dog.ceo/api/breed/${name}/images/random`
1218
);
1319
const result: { message: string } = await response.json();
1420

1521
return result;
1622
},
23+
maxCache: 5,
1724
});
1825

1926
export const About = () => {
2027
// eslint-disable-next-line
2128
const { data, loading, error } = useResource(aboutResource);
29+
const [breedName] = useQueryParam('name');
2230

2331
return (
2432
<div>
25-
<h1>About</h1>
33+
<h1>{breedName}</h1>
2634
<Link to={homeRoute}>Go to home</Link>
2735
<section>
28-
<p>A picture of a schnauzer</p>
29-
<section>
30-
{!loading && <img src={data?.message} alt="A cute dog!" />}
31-
</section>
36+
{!loading && <img src={data?.message} alt="A cute dog!" />}
3237
</section>
3338
</div>
3439
);

examples/routing-with-resources/home.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import { aboutRoute } from './routes';
44

55
export const homeResource = createResource({
66
type: 'home',
7-
getKey: () => 'data',
8-
maxAge: 0,
7+
getKey: () => 'breedList',
8+
maxAge: 10000,
99
getData: async () => {
10-
const response = await fetch('https://dog.ceo/api/breeds/image/random');
10+
const response = await fetch('https://dog.ceo/api/breeds/list/all');
1111
const result: { message: string } = await response.json();
1212

1313
return result;
@@ -17,18 +17,21 @@ export const homeResource = createResource({
1717
export const Home = () => {
1818
// eslint-disable-next-line
1919
const { data, loading, error } = useResource(homeResource);
20+
const breeds = data?.message ? Object.keys(data.message) : [];
2021

2122
return (
2223
<div>
23-
<h1>Home</h1>
24-
<Link to={aboutRoute} prefetch="hover">
25-
Go to about
26-
</Link>
24+
<h1>Dog Breeds</h1>
2725
<section>
28-
<p>A random picture of a cute dog</p>
29-
<section>
30-
{!loading && <img src={data?.message} alt="A cute dog!" />}
31-
</section>
26+
<ul>
27+
{breeds.slice(0, 25).map(breed => (
28+
<li key={breed}>
29+
<Link to={aboutRoute} query={{ name: breed }}>
30+
{breed}
31+
</Link>
32+
</li>
33+
))}
34+
</ul>
3235
</section>
3336
</div>
3437
);

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
{
3737
"name": "Dinesh Pandiyan",
3838
"email": "[email protected]"
39+
},
40+
{
41+
"name": "Prithveesh Goel",
42+
"email": "[email protected]"
3943
}
4044
],
4145
"main": "build/cjs/index.js",
@@ -52,9 +56,9 @@
5256
"build:types-cjs": "tsc --emitDeclarationOnly --project tsconfig.build.json --outDir build/cjs && cp src/*.flow build/cjs",
5357
"build:types-esm": "tsc --emitDeclarationOnly --project tsconfig.build.json --outDir build/esm && cp src/*.flow build/esm",
5458
"docs": "npx docsify-cli serve docs",
55-
"lint": "eslint --ext .ts,.tsx,.js src/",
59+
"lint": "eslint --ext .ts,.tsx,.js src/ examples/",
5660
"lint:deps": "madge -c --extensions ts,tsx src",
57-
"lint:fix": "eslint --ext .ts,.tsx,.js src/ --fix",
61+
"lint:fix": "eslint --ext .ts,.tsx,.js src/ examples/ --fix",
5862
"lint:types": "tsc --noEmit && flow --max-warnings=0",
5963
"lint:types-watch": "tsc --noEmit --watch",
6064
"prepack": "npm run preversion -s && npm run build -s",

src/__tests__/integration/test.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const mockResource = {
3737
getKey: () => 'entry',
3838
getData: () => Promise.resolve('mock-data'),
3939
maxAge: 0,
40+
maxCache: Infinity,
4041
};
4142

4243
const historyBuildOptions = {
@@ -158,6 +159,7 @@ describe('<Router /> integration tests', () => {
158159
key: undefined,
159160
loading: true,
160161
promise: null,
162+
accessedAt: null,
161163
},
162164
},
163165
HI: {
@@ -168,6 +170,7 @@ describe('<Router /> integration tests', () => {
168170
key: undefined,
169171
loading: false,
170172
promise: null,
173+
accessedAt: null,
171174
},
172175
},
173176
});
@@ -205,6 +208,7 @@ describe('<Router /> integration tests', () => {
205208
key: undefined,
206209
loading: false,
207210
promise: expect.any(Promise),
211+
accessedAt: expect.any(Number),
208212
},
209213
},
210214
HI: {
@@ -215,6 +219,7 @@ describe('<Router /> integration tests', () => {
215219
key: undefined,
216220
loading: false,
217221
promise: expect.any(Promise),
222+
accessedAt: expect.any(Number),
218223
},
219224
},
220225
},

src/__tests__/unit/controllers/hooks/resource-store/test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ describe('useResource hook', () => {
137137
...mockSlice,
138138
expiresAt: 100,
139139
data: newData,
140+
accessedAt: 0,
140141
});
141142
});
142143

@@ -162,6 +163,7 @@ describe('useResource hook', () => {
162163
...mockSlice,
163164
expiresAt: 100,
164165
data: newData,
166+
accessedAt: 0,
165167
});
166168
});
167169

0 commit comments

Comments
 (0)