virtua-restoration
Version:
<img src="./virtua-restoration.png" alt="Virtua Restoration" style="max-width: 1000px; width: 100%; display: block; margin: 0 auto 20px auto;">
82 lines (78 loc) • 2.88 kB
JavaScript
// src/components/VirtualizedList.tsx
import { useLayoutEffect, useMemo, useRef } from "react";
import { VList } from "virtua";
// src/components/getCacheProvider.tsx
function getCacheProvider(cacheKey, cacheSource = "sessionStorage", customProvider) {
if (cacheSource === "custom" && customProvider) return customProvider;
const storage = cacheSource === "localStorage" ? window.localStorage : window.sessionStorage;
return {
get: () => {
const serialized = storage.getItem(cacheKey);
if (!serialized) return void 0;
try {
return JSON.parse(serialized);
} catch (e) {
console.error("Error parsing storage cache:", e);
return void 0;
}
},
set: (data) => {
storage.setItem(cacheKey, JSON.stringify(data));
}
};
}
// src/components/VirtualizedList.tsx
import { jsx } from "react/jsx-runtime";
var VirtualizedList = ({ cacheKey, children, cacheSourceType = "sessionStorage", customProvider, className, style }) => {
const ref = useRef(null);
const provider = useMemo(() => getCacheProvider(cacheKey, cacheSourceType, customProvider), [cacheKey, cacheSourceType, customProvider]);
const [offset, cache] = useMemo(() => {
return provider?.get() ?? [];
}, [provider]);
useLayoutEffect(() => {
if (!ref.current) return;
const handle = ref.current;
if (offset) {
handle.scrollTo(offset);
}
return () => {
if (provider) {
provider.set([handle.scrollOffset, handle.cache]);
}
};
}, [offset, provider]);
return /* @__PURE__ */ jsx(VList, { ref, cache, className, style: style ?? { height: "100vh", overflow: "auto" }, children });
};
// src/components/WindowVirtualized.tsx
import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
import { WindowVirtualizer } from "virtua";
import { jsx as jsx2 } from "react/jsx-runtime";
var WindowVirtualizedList = ({ cacheKey, children, cacheSourceType = "sessionStorage", customProvider }) => {
const ref = useRef2(null);
const provider = useMemo2(() => getCacheProvider(cacheKey, cacheSourceType, customProvider), [cacheKey, cacheSourceType, customProvider]);
const [offset, cache] = useMemo2(() => {
return provider?.get() ?? [];
}, [provider]);
useLayoutEffect2(() => {
if (!ref.current) return;
const handle = ref.current;
window.scrollTo(0, offset ?? 0);
let scrollY = 0;
const onScroll = () => {
scrollY = window.scrollY;
};
window.addEventListener("scroll", onScroll);
onScroll();
return () => {
window.removeEventListener("scroll", onScroll);
if (provider) {
provider.set([scrollY, handle.cache]);
}
};
}, [offset, provider]);
return /* @__PURE__ */ jsx2(WindowVirtualizer, { ref, cache, children });
};
export {
VirtualizedList,
WindowVirtualizedList
};