recyclerlistview icon indicating copy to clipboard operation
recyclerlistview copied to clipboard

dataProvider not updating in layoutProvider when using Next JS / SSR

Open Dspritzman opened this issue 3 years ago • 5 comments

I am having trouble getting access to my dataProvider in my layoutProvider while using Next JS. I don't know if it's related to SSR, or if I'm just misusing hooks for my two providers.

The biggest issue is that while my new items are available in the dataProvider as logged by console.log('provider(dataProvider): ', dataProvider); , I am only seeing my initial empty state in my dataProvider when logged in the layoutProvider by console.log('provider(layoutProvider): ', dataProvider); I've added a console screenshot under the code below to make this clearer.

Without the newly added items I can't correctly get their height for the row. You can see how I plan on doing that in the commented out layoutProvider code.

function MainFeedRLV() {
    const [isMounted, setMounted] = useState(false);

    const [isNextPageLoading, setIsNextPageLoading] = useState(false);
    const [items, setItems] = useState([]);
    const [width, setWidth] = useState(1000);
    const [height, setHeight] = useState(1000);
    // Initialize width and height on client, and start rendering RLV
    useEffect(() => {
        setWidth(window.innerWidth);
        setHeight(window.innerHeight);
        setMounted(true)
    }, [])

    const [dataProvider, setDataProvider] = useState(new DataProvider((r1, r2) => {
        return r1.id !== r2.id;
    }).cloneWithRows(items));
    const [layoutProvider, setLayoutProvider] = useState(new LayoutProvider(
        index => {
            console.log('provider(layoutProvider): ', dataProvider);
            console.log('data: ', dataProvider.getDataForIndex(index));
            // const data = dataProvider.getDataForIndex(index);
            // const type = data.containers[0].type;
            return 'test_type';
        },
        (type, dim, index) => {
            console.log('items(layoutProvider): ', items);
            // const height = getHeight(type);
            dim.width = width;
            dim.height = 632;
        }
    ));

    // Update data provider
    useEffect(() => {
        setDataProvider(dataProvider.cloneWithRows(items));
    }, [items]);

    useEffect(() => {
        console.log('dataProvider updated');
        console.log('provider(dataProvider): ', dataProvider);
    }, [dataProvider]);


    // Resize listview to match window
    function updateDimensions() {
        setWidth(window.innerWidth);
        setHeight(window.innerHeight);
    };
    useEffect(() => {
        window.addEventListener('resize', updateDimensions);
        return function cleanup() {
            window.removeEventListener('resize', updateDimensions);
        };
    });

    // Fetch data
    async function fetchMoreData() {
        if (!isNextPageLoading) {
            setIsNextPageLoading(true);
            const newItems = [];
            for (let i = 0; i < 6; i++) {
                const item = TestData.MediumCards;
                newItems.push(item);
            }
            setItems([...items, ...newItems]);
            setIsNextPageLoading(false);
        }
    }

    // Render Rows
    const rowRenderer = (type, data, index) => {
        let storyRow = <StoryRowController data={data} k={index}></StoryRowController>

        return <div>
            <ItemStyle>
                {storyRow}
            </ItemStyle>
        </div>;
    };

    const handleListEnd = () => {
        fetchMoreData();
    };
    
    if (!isMounted) {
        return null;
    }
    const listWidth = Math.min(width, (width / 2) + Constants.MaxCardWidth / 2);
    return (
        <div
            style={{
                display: "flex",
                flexDirection: "column",
                justifyContent: "center",
                alignItems: "center",
                width: listWidth,
                height: height,
            }}>
            <RecyclerListView
                onEndReached={handleListEnd}
                dataProvider={dataProvider}
                layoutProvider={layoutProvider}
                rowRenderer={rowRenderer}
            />
        </div >
    );

    function getHeight(type) {
        ...
    }
}

Here is a screenshot of my console after loading the page. Notice that about 2/3rds the way down the provider(dataProvider) shows 6 items in its data array, while provider(layoutProvider) continues to use the initial, un-updated dataProvider.

RLV

Any help understanding this would be greatly appreciated and I can provide any other needed info.

Dspritzman avatar Dec 02 '21 03:12 Dspritzman

Seems to be an issue with RecyclerListView when using hooks/functional components. I just converted all of this to a class component and it worked.

This is a bug that should probably be fixed or addressed in the readme since functional components are the standard nowadays.

Dspritzman avatar Dec 03 '21 23:12 Dspritzman

@Dspritzman did you find any workaround?

prayaslashkari avatar Jan 12 '22 17:01 prayaslashkari

@callmemonky No, I'm still just using it in a class component which works.

Dspritzman avatar Jan 12 '22 21:01 Dspritzman

in useEffect define new Data Provider in the argument for setting state, i got it working like this in my case, wasn't working earlier

useEffect(() => {
      setDataProvider(new DataProvider((r1, r2) => r1 !== r2).cloneWithRows([...data]))
    }, [data])

Vikram-expertrons avatar Mar 20 '22 05:03 Vikram-expertrons

Having the same issue in the functional component. The above solution didn't work for me. If anybody managed to fix it, please reply. It will be greatly appreciated :)

Alex1899 avatar Apr 10 '22 11:04 Alex1899