Skip to main content

Lazy Load

A performance optimization pattern that loads images only for visible panels by combining the renderOnlyVisible option with the visibleChange event.

import Flicking from "@egjs/flicking";
import "@egjs/flicking/dist/flicking.css";
import "./styles.css";

const TOTAL = 100;
const COLORS = ["#e74c3c", "#3498db", "#2ecc71", "#f39c12", "#9b59b6"];
const getImageUrl = i => `https://picsum.photos/seed/${i}/250/180`;

const camera = document.querySelector(".flicking-camera");
for (let i = 0; i < TOTAL; i++) {
  const panel = document.createElement("div");
  panel.className = "flicking-panel";
  panel.style.background = COLORS[i % COLORS.length];
  panel.innerHTML = `<div class="placeholder">Panel ${i}</div>`;
  camera.appendChild(panel);
}

const loadedSet = new Set();
const infoBar = document.querySelector(".info-bar");

const updateInfo = () => {
  infoBar.textContent = `Images loaded: ${loadedSet.size} / ${TOTAL} (only visible panels are loaded)`;
};

const loadImage = panel => {
  const idx = panel.index;
  if (loadedSet.has(idx)) return;
  loadedSet.add(idx);
  panel.element.innerHTML = `<img src="${getImageUrl(idx)}" alt="Panel ${idx}" />`;
  updateInfo();
};

const flicking = new Flicking("#flick", {
  renderOnlyVisible: true,
  align: "prev",
  bound: true,
  preventDefaultOnDrag: true
});

flicking.on("ready", e => {
  e.currentTarget.visiblePanels.forEach(loadImage);
});

flicking.on("visibleChange", e => {
  e.added.forEach(loadImage);
});

Summary

Key Options/Events

ItemTypeDefaultDescription
renderOnlyVisiblebooleanfalseRender only visible panels
visibleChangeVisibleChangeEvent-Fired when the visible panels change

Event Properties

PropertyTypeDescription
addedPanel[]Panels that newly entered the viewport
removedPanel[]Panels that left the viewport
visiblePanelsPanel[]All currently visible panels

Behavior Comparison

MethodImage Load TimingBest For
Normal loadingAll panels loaded at onceFew panels (10 or less)
Lazy loadingLoaded when entering the viewportMany panels (tens to hundreds)

Details

How It Works

  1. renderOnlyVisible: true renders only visible panels
  2. Detect newly visible panels from the added array in the visibleChange event
  3. Load images for those panels and record the load status
  4. Images that have already been loaded are not loaded again (tracked with a Set)

Initial Load

Since visibleChange has not fired yet right after Flicking initialization, you need to load images for the initially visible panels in the ready event.

  • Relationship with renderOnlyVisible: This option is the core. It reduces DOM overhead by skipping rendering of non-visible panels
  • Relationship with bound: Using bound: true together provides smooth scrolling without empty space at the end
  • Relationship with align: align: "prev" is suitable for list-type layouts

Use Cases

When should you use this?
  • Galleries with many images (50+)
  • Image optimization in infinite scroll feeds
  • Reducing network load in mobile environments

Notes

Caution
  • renderOnlyVisible is recommended for use in framework (React, Vue) environments
  • Panels in the added array of the visibleChange event are Panel objects and can be identified by their index property
  • During initial load, you need to separately handle visible panels in the ready event