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

Items is [] when the component refreshes #146

Closed
phaistonian opened this issue Jun 17, 2021 · 37 comments
Closed

Items is [] when the component refreshes #146

phaistonian opened this issue Jun 17, 2021 · 37 comments
Labels
question Further information is requested

Comments

@phaistonian
Copy link

It seems that when you mount/unmount the component and the itemCount does not change the items is [] (after the first time).

A hacky way out of it is to do something like itemCount: myCount + Math.round(Math.random() * 100) and filter later.

In other words, some kind of check takes place based on the itemCount that causes cache-related (I presume) issues.

@wellyshen
Copy link
Owner

@phaistonian Thank you, I will investigate it soon.

@wellyshen
Copy link
Owner

wellyshen commented Jun 17, 2021

@phaistonian Can you give me a minimal reproduced code snippet or CodeSandbox for this issue? I will check it tomorrow, pretty late in Taiwan, I'm going to sleep.

@wellyshen wellyshen added the question Further information is requested label Jun 17, 2021
@phaistonian
Copy link
Author

it's 11pm down here as well (Greece).

Will see to it tomorrow.

Thank you.

@phaistonian
Copy link
Author

Here's a video that will probably indicate the issue.

It seems this is state-related.

CleanShot.2021-06-17.at.23.44.05.mp4

@wellyshen
Copy link
Owner

@phaistonian I tried to reproduce your case but I can't make it. Did I miss something? Here's the CodeSandbox.

2021-06-18.2.02.31.mov

@phaistonian
Copy link
Author

Indeed, it does work in this - super similar scenario.

I am not sure what the issue is, to be honest.

If you want we can have a zoom call (or have a quick chat) to illustrate the issue — I am afraid I can't share the repo publicly.

@wellyshen
Copy link
Owner

wellyshen commented Jun 18, 2021

@phaistonian Would you mind to simulate your scenario with a CodeSandbox for me? I will check it later.

@phaistonian
Copy link
Author

I will need some time and these days are hectic, plus, this scenario is pretty much identical to what you did.

Does the following help at all?
CleanShot 2021-06-18 at 09 18 38@2x

@wellyshen
Copy link
Owner

@phaistonian Can you check the itemsFiltered.length when there's no filter applied. This hook returns empty items when the itemCount option is falsy.

@phaistonian
Copy link
Author

That's not the issue :(

CleanShot.2021-06-18.at.09.30.31.mp4

@wellyshen
Copy link
Owner

@phaistonian Got it, I think we need a reproduced environment for debugging, plz take your time to prepare it for me. I will think about this case at the same time.

@phaistonian
Copy link
Author

I can give you access to my system (with AnyDesk or something) to take a look.

That would speed things up.

Wanna go that way?

@wellyshen
Copy link
Owner

wellyshen commented Jun 18, 2021

@phaistonian Yes you can invite me, but I will check it later. I think I know your case just not quite sure. If you put the item length as a state or wrap this hook with render items into a component, I think your issue might be solved.

@phaistonian
Copy link
Author

I sense this will solve this too — but this a hack.

@wellyshen
Copy link
Owner

@phaistonian How about put the items length as a state?

@phaistonian
Copy link
Author

Tried it.

That's not it either.

@wellyshen
Copy link
Owner

@phaistonian Plz invite me, I will take time to investigate it.

@phaistonian
Copy link
Author

Let's try whereby https://whereby.com/thebestco

@wellyshen
Copy link
Owner

wellyshen commented Jun 18, 2021

@phaistonian Plz gives me permission to check and run the code (sorry busying now). It will be helpful. I will check it later. Here's my email: hivoid19@gmail.com

@wellyshen
Copy link
Owner

wellyshen commented Jun 18, 2021

Let's try whereby https://whereby.com/thebestco

How to access the code? It like a video chat mate. Do you think we should have a reproduced CodeSandbox here? It can help others as well.

@phaistonian
Copy link
Author

@wellyshen Will try to make some time to do it later.

@wellyshen
Copy link
Owner

@phaistonian Okay, I will check once you provide it.

@phaistonian
Copy link
Author

So, here's how I fixed it.

  • Changing the itemCount in any way, fixes this issue.
  • Used a pseudo flag (isLoading) to switch from zero to the actual count.
  • I still think this is sort of buggy - perhaps some useEffect or useLayoutEffect is acting up

I will try and get a better look later.

CleanShot 2021-06-18 at 13 31 26@2x

@wellyshen
Copy link
Owner

wellyshen commented Jun 18, 2021

@phaistonian Yes, this hook use useLayoutEffect for handling the updating of itemCount. However useLayoutEffect is called before useEffect, but if the itemCount is updated through a state, it shouldn't be a problem. Can you help to double-confirm it? Once I check your reproduced code, I will start to think about the solution (if needed).

@phaistonian
Copy link
Author

Yes - I did confirm it.

If the itemCount remains the same, it's as if it's treated as zero.

Will try and bundle your code to a js file to see where exactly the issue is (bundle from .ts to js).

@wellyshen
Copy link
Owner

wellyshen commented Jun 18, 2021

@phaistonian I need your minimal reproduced code, if you can provide it via CodeSandbox, it will be super helpful.

@phaistonian
Copy link
Author

Got it.

CleanShot 2021-06-18 at 15 26 50@2x

The dependencies to the effect do not change and so this effect is not invoked and so the handleScroll method (nested in the event) is also not called.

My guess is that you need to introduce another dependency that will be reset on unmount (useEffect).

@phaistonian
Copy link
Author

CleanShot 2021-06-18 at 15 42 52@2x

@wellyshen
Copy link
Owner

wellyshen commented Jun 18, 2021

@phaistonian We can't pass the refs to the dependencies they will always trigger the effect function. Because they are object types. What I want to know is under what kind of circumstance that the effect function won't be triggered, that's why I need your help for the reproduced code through CodeSandbox, once I have the reproduced environment, I can solve this problem.

@phaistonian
Copy link
Author

I really can't get it on Codesandbox - it's part of our work repo. Plus decoupling it will take tons of time :(

I might be able to try it on the weekend, can't promise it tho.

@wellyshen
Copy link
Owner

wellyshen commented Jun 18, 2021

@phaistonian Okay, no problem. All I need is the reproduce circumstance, not your business code lol. Take your time mate.

@wellyshen wellyshen assigned phaistonian and unassigned phaistonian Jun 18, 2021
@wellyshen
Copy link
Owner

@phaistonian You can try the latest version of this package to see if this issue still exists or not. If it still exists, leave a reproduce code via CodeSandbox, I will fix it soon.

@phaistonian
Copy link
Author

@wellyshen will do :-) Thanks

@crow7m
Copy link

crow7m commented Aug 15, 2021

@phaistonian You can try the latest version of this package to see if this issue still exists or not. If it still exists, leave a reproduce code via CodeSandbox, I will fix it soon.

Hi, thank you for the great library. was the issue with itemCount fixed ? thank you

@wellyshen
Copy link
Owner

@crow7m Have you encountered the issue?

@wellyshen
Copy link
Owner

Close due to inactive, plz use the latest version to see whether this issue still occurs or not.

@abearief1405
Copy link

Hai @wellyshen first things first I want to thankfull for the library.

I Had similiar issue with this. After successfull render the components, I move to other pages and back to the components, data wont to render it's because isItemLoadedArr[loadIndex] = true.

So I used to const [isItemLoadedArr, setIItemLoadedArr] = useState([]);
create useEffect

useEffect(() => {
    if (isItemLoadedArr.length > 0) {
        const resetIsLoaderArr = isItemLoadedArr.map((dt) => false)
        setIItemLoadedArr(resetIsLoaderArr)
    }

}, []) 

pass isItemLoadedArr to loadMore: (e) => loadData(e, setActivities, isItemLoadedArr)
and the last things pass isItemLoadedArr to const loadData = async ({ loadIndex }, setActivities, isItemLoadedArr) => {...};

This also avoid the callback from being invoked repeatedly.

This is my full code:

import React, { useEffect, useState } from "react";
import useVirtual from "react-cool-virtual";
import axios from "axios";

const api = {
    xxx
}

const loadData = async ({ loadIndex }, setActivities, isItemLoadedArr) => {
    isItemLoadedArr[loadIndex] = true;

    try {
        const { data: activities } = await axios.get(`${api}/${loadIndex + 1}`);

        if (activities.data !== null) {
            setActivities((prevActivities) => {
                const nextActivities = [...prevActivities];

                activities.data.forEach((comment) => {
                    nextActivities[comment.id - 1] = comment;
                });

                return nextActivities;
            });
        } else {
            isItemLoadedArr[loadIndex] = false;
        }
    } catch (err) {
        isItemLoadedArr[loadIndex] = false;
        loadData({ loadIndex }, setActivities, isItemLoadedArr);
    }
};

const DataActivities = ({ total }) => {
    const cActivities = total;
    const batchActivities = 5;

    const [isItemLoadedArr, setIItemLoadedArr] = useState([]);
    const [activities, setActivities] = useState([]);
    const { outerRef, innerRef, items } = useVirtual({
        itemCount: cActivities,
        itemSize: 400,
        loadMoreCount: batchActivities,
        isItemLoaded: (loadIndex) => isItemLoadedArr[loadIndex],
        loadMore: (e) => loadData(e, setActivities, isItemLoadedArr)
    });

    useEffect(() => {
        if (isItemLoadedArr.length > 0) {
            const resetIsLoaderArr = isItemLoadedArr.map((dt) => false)
            setIItemLoadedArr(resetIsLoaderArr)
        }

    }, [])

    return (
        <div
            className="outer"
            style={{ width: "300px", height: "500px", overflow: "auto" }}
            ref={outerRef}
        >
            <div ref={innerRef}>
                {items.map(({ index, measureRef }) => (
                    <div
                        key={activities[index]?.id || `fb-${index}`}
                        className={`item ${index % 2 ? "dark" : ""}`}
                        style={{ padding: "16px", minHeight: "122px" }}
                        ref={measureRef} // Used to measure the unknown item size
                    >
                        {activities[index]
                            ? `${activities[index].id}. ${JSON.stringify(activities[index])}`
                            : "⏳ Loading..."}
                    </div>
                ))}
            </div>
        </div>
    );
};

export default DataActivities;

Hope it's help, thank you.

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

No branches or pull requests

4 participants