-
-
Notifications
You must be signed in to change notification settings - Fork 314
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Redundant repaints, because of ResizeObserver. It send events when when list got hiden with css display property. #823
Comments
Hi, yes it's know issue as the RO callback will be called when changing display. One option could be to pass custom measureElement that will skip those updates const updateSize = isTabVisible
measureElement: (
element: TItemElement,
entry: ResizeObserverEntry | undefined,
instance: Virtualizer<TScrollElement, TItemElement>,
) => {
const getSize = () => measureElement(element, entry, instance)
if (updateSize) {
return getSize()
} else {
const item = instance.measurementsCache[instance.indexFromElement(element)]
return item ? item.size : getSize()
}
}, Other using the |
What do you mean by Also, example with custom |
Ooo sorry you are right, before it was working, need to check it. |
hi, I encountered the same issue, and here is my solution.
const updateActiveTab = useCallback((val: string) => {
emitter.emit('onBeforeTabChange', val);
dispatch(updateAppState({currentActiveTab: val}));
emitter.emit('onAfterTabChange', val);
}, [dispatch]);
import mitt from 'mitt';
type Events = {
onBeforeTabChange: string;
onAfterTabChange: string;
};
const emitter = mitt<Events>();
export default emitter;
import { useEffect, useState } from "react";
import { useAppSelector } from "../store/hooks";
import emitter from "../util/emitter";
export function useVirtualizerScrollElementAvailable(tabKey: string) {
const currentActiveTab = useAppSelector(state => state.app.currentActiveTab);
const [isScrollContainerAvailable, setIsScrollContainerAvailable] = useState(currentActiveTab === tabKey);
useEffect(() => {
const onBeforeTabChangeHandler = (val: string) => {
val !== tabKey && setIsScrollContainerAvailable(false);
};
const onAfterTabChangeHandler = (val: string) => {
val === tabKey && setTimeout(() => setIsScrollContainerAvailable(true), 0);
};
emitter.on('onBeforeTabChange', onBeforeTabChangeHandler);
emitter.on('onAfterTabChange', onAfterTabChangeHandler);
return () => {
emitter.off('onBeforeTabChange', onBeforeTabChangeHandler);
emitter.off('onAfterTabChange', onAfterTabChangeHandler);
};
}, [tabKey]);
return {
isScrollContainerAvailable,
};
}
const { isScrollContainerAvailable } = useVirtualizerScrollElementAvailable(tabKey);
const virtualizer = useVirtualizer({
count: visiblePerks.length,
// The virtual list remains intact when the tab is hidden.
// Without this handling, the virtual list will be destroyed and re-rendered when the tab is shown again.
getScrollElement: () => isScrollContainerAvailable ? listRef.current : null,
estimateSize: () => 180,
overscan: 1,
}); |
Other option would be to skip updates of RO, something like this const updateSizeRef = useLatestRef(updateSize ?? true)
const virtualizer = useVirtualizer({
measureElement: (element, entry, instance) => {
if (updateSizeRef.current) {
return measureElement(element, entry, instance)
} else {
return notUndefined(instance.measurementsCache[instance.indexFromElement(element)]).size
}
},
observeElementRect: (instance, cb) => {
return observeElementRect(instance, rect => {
if (updateSizeRef.current) {
cb(rect)
} else {
cb(instance.scrollRect ?? rect)
}
})
},
...options,
}) Maybe it should be build in into library? |
It would be great |
I have the same issue of the virtualized list flickering when I switch tabs, e.g. switching back from tab2 to tab1. (the virtualized list is in tab1). The problem is that I have an input filter with the virtualized list and every time I switch back to the tab, the empty text is displayed first and then the items. However, the empty text should only appear if no items match the filter text. Thanks for the hint @ekoooo I solve the flicking issue with only one line change: getScrollElement: () => tab === "tab1" ? listRef.current : null, |
Describe the bug
Hi, I have app that has tabbed view with multiple lists. When tab switched all elements in list disapears. After it went back to visible state, list got rerender.
Tab view implemented as such:
Things that happens:
#tab_1
, 30 elements rendered within<VirtualList>
#tab_2
#tab_1
style property changed fromblock
->none
<VirtualList/>
within#tab_1
notified via resize observer, with event where all sizes === 0#tab_1
got unmounted#tab_2
style property changed fromnone
->block
<VirtualList/>
within#tab_2
notified via resize observer with current view size<VirtualList/>
within#tab_2
populated with visible elementsThe problem with this behaviour is that elements getting rerendered when user switch tabs. In most cases it is not a big problem, but in my case it make lot's of flickering, because list displays elements with images. And for some reason, images couldn't be displaye immediatly. Also it just useless work that browser should redo each time user show/hide lists.
Your minimal, reproducible example
https://stackblitz.com/edit/vitejs-vite-1ucf3g?file=src%2FApp.tsx
Steps to reproduce
Expected behavior
It would be great, if handler of ResizeObserver checks if
offsetParrent
of observed element is not equal tonull
. It it is, that means that observed element is invisible, and all layouting/rerendering of list should be skipped.Or at least, there should be some flag that allows to skip such rerenders.
How often does this bug happen?
Every time
Screenshots or Videos
No response
Platform
Windows 10
Chrome 128
tanstack-virtual version
solid-virtual 3.10.6
TypeScript version
5.4.5
Additional context
No response
Terms & Code of Conduct
The text was updated successfully, but these errors were encountered: