perf: 资料流会话级缓存,切换页面不再重载
usePostStream 增加按筛选参数为 key 的内存缓存,保存已加载的全部内容与分页 游标。再次进入同一视图(如首页⇄全部资料来回切)时直接还原,不重置、不重新 请求、不显示骨架屏。整页刷新清空缓存以获取最新数据。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -94,6 +94,24 @@ function buildRealUrl(params: PostStreamParams, cursor?: string): string {
|
||||
return `${q ? "/api/posts/search" : "/api/posts"}?${sp.toString()}`;
|
||||
}
|
||||
|
||||
type CachedStream = {
|
||||
items: Post[];
|
||||
cursor: string | undefined;
|
||||
hasMore: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Session cache of loaded stream state, keyed by the request params. Lets a
|
||||
* view that's been seen before (e.g. switching Home ⇄ All) restore instantly —
|
||||
* all loaded pages, no skeleton, no refetch — instead of reloading from page 1.
|
||||
* In-memory only: a full page reload starts fresh.
|
||||
*/
|
||||
const streamCache = new Map<string, CachedStream>();
|
||||
|
||||
function streamKey(params: PostStreamParams): string {
|
||||
return buildRealUrl(params);
|
||||
}
|
||||
|
||||
export function usePostStream(params: PostStreamParams): PostStreamResult {
|
||||
const [items, setItems] = useState<Post[]>([]);
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
@@ -172,6 +190,17 @@ export function usePostStream(params: PostStreamParams): PostStreamResult {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// Restore a previously-loaded view instantly (no reset, no refetch).
|
||||
const cached = streamCache.get(streamKey(params));
|
||||
if (cached) {
|
||||
setItems(cached.items);
|
||||
cursorRef.current = cached.cursor;
|
||||
setHasMore(cached.hasMore);
|
||||
hasMoreRef.current = cached.hasMore;
|
||||
setIsLoading(false);
|
||||
setError(null);
|
||||
return;
|
||||
}
|
||||
setItems([]);
|
||||
cursorRef.current = undefined;
|
||||
setHasMore(true);
|
||||
@@ -188,6 +217,17 @@ export function usePostStream(params: PostStreamParams): PostStreamResult {
|
||||
params.lang,
|
||||
]);
|
||||
|
||||
// Persist loaded state so returning to this view restores it from cache.
|
||||
useEffect(() => {
|
||||
if (items.length === 0) return;
|
||||
streamCache.set(streamKey(params), {
|
||||
items,
|
||||
cursor: cursorRef.current,
|
||||
hasMore,
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [items, hasMore]);
|
||||
|
||||
const loadMore = useCallback(() => {
|
||||
fetchPage(false);
|
||||
}, [fetchPage]);
|
||||
|
||||
Reference in New Issue
Block a user