Skip to content

Instantly share code, notes, and snippets.

@edzis
Created February 16, 2022 16:03
Show Gist options
  • Save edzis/e97d83ee4eb7bf016f5dff165244ebd5 to your computer and use it in GitHub Desktop.
Save edzis/e97d83ee4eb7bf016f5dff165244ebd5 to your computer and use it in GitHub Desktop.
Image component that uses Blob URLs acquired via React Query with createObjectURL and cleanup with revokeObjectURL.
import React from 'react';
import { Query, useQuery } from 'react-query';
const QUERY_KEY_BASE = 'BlobImage';
const BLOB_URL_CACHE_TIME = 5000;
const DEBUG = process.env.NODE_ENV === 'development' && true;
type ImageProps = React.ImgHTMLAttributes<HTMLImageElement>;
const useBlobImageUrl = (src: ImageProps['src']) => {
const { data: blobUrl } = useQuery(
[QUERY_KEY_BASE, src],
async () => {
if (!src) {
return;
}
const res = await global.fetch(src);
const blob = await res.blob();
const url = URL.createObjectURL(blob);
if (DEBUG) {
console.log('BlobImage createObjectURL', url);
}
return url;
},
{ staleTime: Infinity, cacheTime: BLOB_URL_CACHE_TIME },
);
return blobUrl;
};
export const maybeRevokeBlobImageUrl = (query: Query) => {
if (
typeof query.state.data !== 'string' ||
query.queryKey[0] !== QUERY_KEY_BASE
) {
return;
}
const url = query.state.data;
if (DEBUG) {
console.log('BlobImage revokeObjectURL', url);
}
URL.revokeObjectURL(url);
};
const BlobImage: React.VFC<ImageProps> = ({ src, ...rest }) => {
const blobUrl = useBlobImageUrl(src);
return <img src={blobUrl} {...rest} />;
};
export default BlobImage;
import { default as React } from 'react';
import { render } from 'react-dom';
import { QueryClient, QueryClientProvider } from 'react-query';
import BlobImage, { maybeRevokeBlobImageUrl } from './BlobImage';
const queryClient = new QueryClient();
queryClient.getQueryCache().subscribe((event) => {
if (!event) {
return;
}
if (event.type === 'queryRemoved') {
maybeRevokeBlobImageUrl(event.query);
}
});
const Main = () => {
return (
<>
<QueryClientProvider client={queryClient}>
<BlobImage src="some/path/that/returns/a/blob" />
</QueryClientProvider>
</>
);
};
const root = document.getElementById('root');
render(<Main />, root);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment