Giter Site home page Giter Site logo

Comments (7)

oleggrishechkin avatar oleggrishechkin commented on May 27, 2024 1

@kiejo , good suggestion (thought about it, but not tried)

Also different threshold of intersection can be used with really small steps - like [0.001, 0.002..., 1] to catch shifts/changes in intersection - but intersection handler can evaluate frequently and not cover cases where 0.001 is hundreds of pixels.

from react-viewport-list.

oleggrishechkin avatar oleggrishechkin commented on May 27, 2024

Hi, @kiejo
Most other virtualization libs use simple onscroll event. I tried some approaches with onscroll/intersection observer/non endless animation frame but unsuccessfully.

I think intersection observer for spacers (a div which fills virtualized space) can be used and I made some drafts with it a time ago. Mostly it works fine. I want to move to this solution in future if I'll make it good in all cases.

I need a way to know when elements changed their positions near viewport - it can be scroll, parent resize, shifts by elements added on top/bottom, window resize, item height change... Endless request animation frame handle all of these "events".

from react-viewport-list.

kiejo avatar kiejo commented on May 27, 2024

Thanks for the quick answer and explanation! Using an intersection observer that spans the list's viewport sounds like a good potential approach to detect when elements move out of or into the viewport. I will have to look at the current implementation in more detail to better understand how everything works at the moment.
It's great to hear that it's a topic that is already on your radar and that might get addressed in the future. Thanks for the great library!

from react-viewport-list.

oleggrishechkin avatar oleggrishechkin commented on May 27, 2024

@kiejo I can explain current logic deeply.

Every frame I compute rects of spacers, first/last rendered list items and viewport bounds. Then I check is everything shown inside viewport without free spaces. If I need to render more items, I change "indexes to render", but it's some kind of estimation - at next frame indexes may be corrected.

Logic now: render some items -> check that all items fill viewport -> correct indexes to fill viewport.

When you scroll last item can be fully intersect the viewport - this is the moment I change indexes for example.

from react-viewport-list.

kiejo avatar kiejo commented on May 27, 2024

That's an interesting approach. It sounds like an IntersectionObserver with the list container as its root could be used to detect whenever a spacer element intersects (or stops intersecting) with the list rect. Whenever the spacer intersects, more items would need to be rendered until the observer fires again indicating that the spacer does not intersect anymore and got pushed out of the list rect. The rootMargin of the observer could be used to handle an overscan so that new items are rendered sooner.
A similar mechanism could be used to detect when items need to be removed. A second observer with a wider rootMargin could be used to check when a spacer element gets pushed too far out of the list rect. That would indicate that items can be removed from the DOM.

I haven't tried any of this, but in theory I think this could potentially handle cases like scrolling, parent/window resize, new elements being added within the rendered range, and height changes of rendered items.
I'm sure there are many more cases to handle and and an approach like this would need more exploration and prototyping to verify if it's actually viable. I also don't know what the overall performance would then look like, but the idle CPU usage should definitely be lower if this approach works.

It sounds like you may have already thought about something like this as you mentioned you already made some drafts using IntersectionObserver. Just thought I'd share some ideas in case you haven't thought about some of these yet.

from react-viewport-list.

oleggrishechkin avatar oleggrishechkin commented on May 27, 2024

@kiejo Yes, I made exactly you described with IntersectionObserver. The problem with observer is it fired only once - when "intersection" changed. So bad case is when spacer intersect viewport, we render new items, but new rendered items not fill the free spaces and spacer still intersect viewport - at this case virtualization will be broken. I fix it by reobserve anytime on indexes change (this is a part where rAF is more performant) - but this sulution has some pitfalls too. Also I tried to use "check" on layout effect instead of reobserve on index change and catch max state update error in react sometimes 😅

Anyway I think intersection observer is a good way to "make it right" without hacky rAF.

from react-viewport-list.

kiejo avatar kiejo commented on May 27, 2024

Good to hear that you already tried this approach :)

The problem with observer is it fired only once - when "intersection" changed. So bad case is when spacer intersect viewport, we render new items, but new rendered items not fill the free spaces and spacer still intersect viewport - at this case virtualization will be broken.

Maybe something like this could help with this case:
Whenever the observer gets notified about the spacer intersecting, start an update loop that keeps adding more items until the observer gets notified that the spacer does not intersect anymore.

function update() {
  // Needs to stop the update loop when the start/end of the items array is reached and the
  // items do not take enough space to push the spacer element out of the list rect (prevent
  // endless update loop).
}

let frameId = null
function updateLoop() {
  frameId = requestAnimationFrame(updateLoop)
  update()
}

function startUpdateLoop() {
  if (!frameId)
    updateLoop()
}

function stopUpdateLoop() {
  if (frameId) {
    cancelAnimationFrame(frameId)
    frameId = null
  }
}

const observer = new IntersectionObserver(entries => {
  if (entries[0].isIntersecting)
    startUpdateLoop()
  else
    stopUpdateLoop()
}, {
  root: listElement,
  threshold: 0,
})

observer.observe(spacerElement)

This is just some ideation on how this could potentially work and I'm sure the logic would need to handle more cases.

from react-viewport-list.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.