Files
NapCatQQ/.pnpm-store/v3/files/b2/abf304ba14db838682a6c4554956d08a44b2b5d451044abb636f3b39cd9fb5bfc1fb67d738115ba98fc4e802cef2badfe8f3181679345cb575ece90f22af94
T
TanTan e311ca3275
Build NapCat Artifacts / Type Check & Test (push) Waiting to run
docs: 仓库链接指向本镜像仓库
2026-11-13 09:25:58 +08:00

121 lines
3.8 KiB
Plaintext

/*
* Copyright 2020 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import {Collection, Key} from '@react-types/shared';
import {InvalidationContext} from './types';
import {Layout} from './Layout';
import React, {useCallback, useMemo, useRef, useState} from 'react';
import {Rect} from './Rect';
import {ReusableView} from './ReusableView';
import {Size} from './Size';
import {Virtualizer} from './Virtualizer';
// During SSR, React emits a warning when calling useLayoutEffect.
// Since neither useLayoutEffect nor useEffect run on the server,
// we can suppress this by replace it with a noop on the server.
export const useLayoutEffect: typeof React.useLayoutEffect = typeof document !== 'undefined'
? React.useLayoutEffect
: () => {};
interface VirtualizerProps<T extends object, V, O> {
renderView(type: string, content: T | null): V,
layout: Layout<T>,
collection: Collection<T>,
onVisibleRectChange(rect: Rect): void,
persistedKeys?: Set<Key> | null,
layoutOptions?: O
}
export interface VirtualizerState<T extends object, V> {
visibleViews: ReusableView<T, V>[],
setVisibleRect: (rect: Rect) => void,
contentSize: Size,
virtualizer: Virtualizer<T, V>,
isScrolling: boolean,
startScrolling: () => void,
endScrolling: () => void
}
export function useVirtualizerState<T extends object, V, O = any>(opts: VirtualizerProps<T, V, O>): VirtualizerState<T, V> {
let [visibleRect, setVisibleRect] = useState(new Rect(0, 0, 0, 0));
let [isScrolling, setScrolling] = useState(false);
let [invalidationContext, setInvalidationContext] = useState<InvalidationContext>({});
let visibleRectChanged = useRef(false);
let [virtualizer] = useState(() => new Virtualizer<T, V>({
collection: opts.collection,
layout: opts.layout,
delegate: {
setVisibleRect(rect) {
setVisibleRect(rect);
visibleRectChanged.current = true;
},
// TODO: should changing these invalidate the entire cache?
renderView: opts.renderView,
invalidate: setInvalidationContext
}
}));
// onVisibleRectChange must be called from an effect, not during render.
useLayoutEffect(() => {
if (visibleRectChanged.current) {
visibleRectChanged.current = false;
opts.onVisibleRectChange(visibleRect);
}
});
let mergedInvalidationContext = useMemo(() => {
if (opts.layoutOptions != null) {
return {...invalidationContext, layoutOptions: opts.layoutOptions};
}
return invalidationContext;
}, [invalidationContext, opts.layoutOptions]);
let visibleViews = virtualizer.render({
layout: opts.layout,
collection: opts.collection,
persistedKeys: opts.persistedKeys,
layoutOptions: opts.layoutOptions,
visibleRect,
invalidationContext: mergedInvalidationContext,
isScrolling
});
let contentSize = virtualizer.contentSize;
let startScrolling = useCallback(() => {
setScrolling(true);
}, []);
let endScrolling = useCallback(() => {
setScrolling(false);
}, []);
let state = useMemo(() => ({
virtualizer,
visibleViews,
setVisibleRect,
contentSize,
isScrolling,
startScrolling,
endScrolling
}), [
virtualizer,
visibleViews,
setVisibleRect,
contentSize,
isScrolling,
startScrolling,
endScrolling
]);
return state;
}