Swiper Virtual Slide Recycler and React Wrapper: Memory Release on Dynamic Slide Count Changes
0 reputation · 11 Dec 2020, 12:01 UTC
0 reputation · 11 Dec 2020, 12:01 UTC
Confirm that Swiper’s virtual slide recycler releases detached DOM nodes when the slide array length changes at runtime while using the official React wrapper in a long‑lived single‑page application.
The recycler is designed to reuse slide elements, but it is unclear whether it properly disposes of nodes that become detached after a slide count reduction, which could lead to unbounded memory growth.
Specific questions:
34775 reputation · 11 Dec 2020, 16:09 UTC
1. Does the virtual slide recycler trigger cleanup for each removed slide when the slide array shrinks? No. Swiper's virtual implementation keeps a fixed pool of DOM elements sized to slidesPerView plus a buffer. When the data array shrinks, the excess pooled nodes are not destroyed; they stay in the internal recycler for potential reuse if the array grows again.
2. Are the detached DOM nodes eligible for garbage collection, or do they remain referenced? They remain referenced. The Swiper instance holds them in private properties virtual.slides (array) and virtual.slideElements (Map), preventing GC until the Swiper instance itself is destroyed.
3. What observable behavior can be inspected to verify proper release without modifying Swiper source? Compare the live swiper.virtual.slideElements.size against the current data array length, and take heap snapshots filtered by the slide class (e.g., HTMLDivElement.swiper-slide) before and after a reduction. The map size and detached node count will stay at the historical peak.
Swiper's virtual mode (core, not React-specific) creates a sliding window of real DOM nodes that are reused as the user scrolls. The pool size is determined at initialization by slidesPerView + slidesPerGroup + buffer. The React wrapper (swiper/react) reconciles the data array and re-renders slide components, but it does not instruct the core to shrink its internal element cache. Consequently:
useEffect return functions) run for each removed slide component, so your component-level listeners and subscriptions are released.<div class=\"swiper-slide\"> elements stay attached to the Swiper instance's private cache, along with any listeners the core attached (lazy-load, touch, transition handlers).Behavior described matches Swiper 9.x through 11.x (virtual internals were refactored in v9 and again in v11). The React wrapper version must match the core version; mismatched versions can cause undefined recycler behavior. If you are on Swiper 8.x, the cache mechanism differs but the retention principle is similar.
HTMLDivElement or the class swiper-slide.const swiper = document.querySelector('.swiper').swiper;
console.log('slideElements map size:', swiper.virtual.slideElements.size);
console.log('virtual.slides array length:', swiper.virtual.slides.length);
console.log('data array length:', swiper.virtual.slides.length); // or your React state length
The map size will reflect the peak, not the current length.swiper.destroy(true, true) and reinitialize; a third snapshot should show memory return to baseline, confirming the recycler was the retention source.swiper.destroy(true, true) then re-mount the React component). This clears the recycler.slidesPerView + buffer at the maximum historical data length. The growth is bounded, not unbounded.What is the typical peak slide count and frequency of reductions in your SPA? If peak is under a few hundred and reductions are rare, the retained memory is likely negligible. If peak reaches thousands and reductions happen on every filter keystroke, the recycler cache may become a measurable leak and destroying/reinitializing on each change may be necessary.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.