Svelte re-rendering a virtual list of images causes images to flicker

I’m not sure if I should be posting this here or adding to svelte creators github, but I have a problem here which may need a fix to be applied on the svelte side.

I am trying to render a virtual list of images, by only having the images that are shown in the viewport, in the DOM.

Here’s a basic REPL reproducing the issue:
https://svelte.dev/repl/d6c4617ada3b47d8b197b0e67820eba7?version=3.42.4

On my computer I only see it very clearly if I use chrome and open up dev tools for some reason. As I scroll the grid and the list of images added to the DOM changes, the images flicker.

It’s as if the DOM Manipulations that Svelte does are causing this.

It seems that, as we scroll the next items into the view, and hide the previous items, the svelte Dom manipulations algorithm, changes the positions and sources of ALL images present on the virtual grid, to show the appropriate ones in the viewport.

If instead it was able to reconcile the items in the list and keep the ones that stay in the viewport on scroll not changing, and therefore not blinking (and I think also sending a network request) it would be great.

I’m not sure if it’s possible to achieve this, without working directly with svelte code.

Perhaps manipulating the item list in multiple steps, but not sure how that would work.

Answer

There are two parts to this:

  1. This happens with open dev tools because you very likely have “disable cache” enabled. This means that all images are reloaded every time they appear as part of a new image element. Without dev tools open or with “disable cache” disabled, the results are cached and the flickering won’t appear
  2. You reassign the list with new items every time, and Svelte has no knowledge that it could reuse an existing node and just reorder it. You can “help” Svelte here though and give it a hint to achieve this: You need to specify a key which uniquely identifies each item. This is called a “keyed each block”. If you change your each block to {#each tiles as tile (tile.im)} you tell Svelte that the im property is the one to uniquely identify an item, and then Svelte is able to reuse existing nodes. Docs: https://svelte.dev/docs#each