Skip to content

Instantly share code, notes, and snippets.

@ryanflorence
Last active February 8, 2023 06:45
Show Gist options
  • Save ryanflorence/e10cc9dbc0e259759ec942ba82e5b57c to your computer and use it in GitHub Desktop.
Save ryanflorence/e10cc9dbc0e259759ec942ba82e5b57c to your computer and use it in GitHub Desktop.
import React from "react";
import { Link } from "react-router-dom";
export function createResource(getPromise) {
let cache = {};
let inflight = {};
let errors = {};
function load(key) {
inflight[key] = getPromise(key)
.then(val => {
delete inflight[key];
cache[key] = val;
})
.catch(error => {
errors[key] = error;
});
return inflight[key];
}
function preload(key) {
if (cache[key] !== undefined || inflight[key]) return;
load(key);
}
function read(key) {
if (cache[key] !== undefined) {
return cache[key];
} else if (errors[key]) {
throw errors[key];
} else if (inflight[key]) {
throw inflight[key];
} else {
throw load(key);
}
}
function clear(key) {
if (key) {
delete cache[key];
} else {
cache = {};
}
}
function ResourceLink({ cacheKey, ...props }) {
const _preload = () => preload(cacheKey);
return (
<Link onMouseEnter={_preload} onFocus={_preload} {...props} />
);
}
return { preload, read, clear, Link: ResourceLink };
}
@ryanflorence
Copy link
Author

ryanflorence commented Dec 17, 2019

Usage:

// resources.js
import { createResource } from "./createResource";

const API = createResource(url => (
  fetch(url).then(res => res.json())
);

const FirebaseDoc = createResource(path => (
  firebase.firestore().doc(path).get()
))

export { API, FirebaseDoc }
// somefile.js
import { API } from './resources'

API.preload('/thing')
const stuff = API.read('/thing')
API.clear('/thing')
API.clear() // all keys
<API.Link to="/wherever" cacheKey="/thing"/>

@derekr
Copy link

derekr commented Dec 17, 2019

Cache key on the resource link is p dope!

@AndresRodH
Copy link

Preloading data on mouse enter is so nice! 🤯

Btw, there's a typo on the API.Link usage example on cachKey -> cacheKey 😄

@SleeplessByte
Copy link

When using any HTTP Caching RFC compliant service, putting https://github.com/kornelski/http-cache-semantics in the middle before storing something in a cache (ie lru-cache) is probably something you'll want to do to remove a lot of subtle bugs.

In other words, for most projects the above will probably be Good Enough:tm:, but if you want to respect Cache-Control, I don't recommend "globally" caching the req/res -- at least store it in the component state so you get something fresh if you re-create the component.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment