Skip to content
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

Gallery virtualization #92

Open
Robinnnnn opened this issue Apr 16, 2021 · 0 comments
Open

Gallery virtualization #92

Robinnnnn opened this issue Apr 16, 2021 · 0 comments
Labels

Comments

@Robinnnnn
Copy link
Contributor

Robinnnnn commented Apr 16, 2021

Gallery Virtualization Strategy

We'll need to virtualize a user's gallery in order to minimize UX jank and unnecessary network requests. This is particularly important given the heftiness of NFTs and some of them being large, high-res videos. This article does a great job summarizing the approach.

The industry standard library to accomplish virtualization is react-window, which is by the same author who wrote the preceding react-virtualized. Data efficiency around loading each asset should be handled out-of-the-box, since an unrendered literally won't trigger a network request.

The problem

Unfortunately, virtualization tools rely heavily on the height of each row being known in advance. In other words, it wants to have an idea of the scaffolding needed for your list (or grid) before anything renders.

This is easy to deal with if the elements within your grid have uniform height (e.g. chess board), and becomes a lot more difficult if each row has varying heights (e.g. gallery with both tall and short NFTs). We also can't use the tallest possible NFT as a bottleneck, as this would stretch out each row to be taller than necessary, and cause otherwise normal-sized NFTs to be spread out. Discussion around this issue can be found here: bvaughn/react-window#190

The solution(s)

There are two potential solutions:

  1. Variable Size List. This supports rows of varying sizes. However, this still requires the a known height for each row in advance. We can do this by storing the dimensions of each NFT in the database, and retrieving those dimensions when loading a user's gallery:
const collection = [
  { id: 1, width: 500, height: 500 },
  { id: 2, width: 200, height: 800 },
  { id: 3, width: 300, height: 300 },
  ...
]

Then we can use the user's current browser width to determine the max height + width for any NFT, and apply that against the aspect ratio from the server. We'll also need to know how many columns the user should see (again from browser width) to finalize the height of each row. For example, a tall NFT may appear on row 1 / col 3 in desktop view, but row 3 / col 1 in mobile view, affecting the heights we assign to each row for the virtualizer.

The only downside to the approach is a) storing extra metadata on the server and b) client-side computations we'll have to perform on fetch. We can mitigate b) by having the server handle the aspect ratio for each screen width as a pre-processing step, like so:

const NFT = {
  id: 1,
  dimensions: {
    original: { width: 10000, height: 10000 },
    desktop: { width: 500, height: 500 },
    tablet: { width: 450, height: 450 },
    mobile: { width: 400, height: 400 }
  }
}
  1. Dynamic Size List. In theory, this supports variable list sizes without knowing row heights in advance. This uses just-in-time measuring of each row based on its content, and is outlined here: Support just-in-time measured content bvaughn/react-window#6. This feature is only available as an alpha and does exhibit some issues around jittery scroll position.

DynamicSizeList would make our lives a lot easier. We should try this first, see if it works for our use case, and resort to VariableSizeList as a backup.

Another problem ...

Not only will the rows be varying heights, but there will also be intermittent collection headers we'll have to squeeze in (e.g. title, description, whitespace). This is arguably more challenging than the image issue since the server can't tell us how "tall" someone's description text will be.

... and another solution

We should be able to solve this by giving all collection headers a fixed height and virtualizing it themselves, by interspersing them within the array of NFTs. Feels a bit hacky but there should be a clean solution.

It may also be a bit awkward if a collection has no title while another has a full title + long description. Perhaps we could guesstimate the height of a collection header simply by checking whether a title and/or description exists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant