-1

I try to make some kind of infinite scroll

Here is my CodeSandbox setup (first approach)

To paginate I made some kind of cursor which keeps last loaded item id in after state variable

I use that after value in a handleLoadMore, which is passed as parameter to my custom LoadMore component. When page loaded, I can trigger first handleLoadMore with correct after value, but all following requests are uses it's first value (59 in my case)

I guess thats due to the fact that handleLoadMore is created during first render of LoadMore component. To proof it I added loading state variable, which controls wheither LoadMore component is rendered:

// App.tsx
...    
export default function App() {
    const [loading, setLoading] = useState(false);
    ...
    const handleLoadMore = () => {
        setLoading(true);

        setTimeout(() => {
            ... // receive another batch
            setLoading(false);
        }
    }
    ...
    return (
        ...
        // <LoadMore onLoadMore={handleLoadMore} />}
        {!loading && <LoadMore onLoadMore={handleLoadMore} />}
        ...
    )
}

You may check it here (second approach). And this variant works as I expect. That's because with every change of loading from true to false LoadMore component is rerendered, so it's handleLoadMore redefined with new after value. But I don't think this approach is correct - I want to keep LoadMore component visible all the time

What could be done is make onLoadMore handler parametric and pass after value to it like:

// LoadMore.tsx
...
interface LoadMoreProps {
    // onLoadMore: () => void;
    onLoadMore: (after: number) => void;
    after: number
}

export default ({ onLoadMore, after }: LoadMoreProps) => {
    useEffect(() => {
        ...
        const observer = new IntersectionObserver((entries: any) => {
            ...
            if (entry.isIntersecting) {
                // onLoadMore();
                onLoadMore(after);
            }
        }, options);
        ...
    }, [loaderRef?.current]);
}
...

But I want to keep LoadMore component independent of my pagination technique (here I use some kind of cursor, but it might be page index or whatever)

So, what is the reason for such behaviour in my first approach? Is there any way clean and proper to make onLoadMore use actual value of after variable?

There is also an side question, but I will ask it here - after triggering handleLoadMore page freezes for a few moments - may be feelable if you scroll to bottom and immideately scroll to top - it will not respond, cannot fugure out why

1 Answer 1

1

After looking at your live demo, this seems like this is a closure related issue in React.

In the original code, handleLoadMore captures the value of after at the time of its creation. If this changes later, then handleLoadMore will still refer to the old value since it was defined in the initial scope of this render. This means that every time LoadMore component is using the handleLoadMore, it's still using the initial version of it.

Personally, I would use a ref to access the current value of after, while also keeping the handleLoadMore more stable.

As for your side question, this may help. After a quick google search I was able to find that apparently requestIdleCallback or requestAnimationFrame may be of assistance if you're using non-urgent UI updates.

Let me know if this is helpful, or if I may be able to provide some more assistance for you!

Sign up to request clarification or add additional context in comments.

3 Comments

No problem, not too sure if this will entirely work, as I'm still a student learning. But I do have at least 2 years React Experience. Seems like a cool project and should be something to show off. Happy Coding!
yep, that's what I suggest happend here. Could you explain how to pass after value via ref (i.e. reference, not value, I guess) and yep, I already heard of requestAnimationFrame, even though never used it. The problem is I cannot get why it freezes, not yet how to fix it apps I develop is for small company, doubt anybody will notice something wrong, in prod it barely feelable, but I as developer should know whats going on btw I practice React since 2019, but that's not my main specialization
You can pass after value via ref by following these steps: 1. Create the Ref tsx const afterRef = useRef(after); 2. Keep it updated tsx useEffect(() => { afterRef.current = after; }, [after]); 3. Use it in a callback tsx const handleLoadMore = () => { const currentAfter = afterRef.current; // Use currentAfter to fetch the next page };

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.