recyclerlistview
recyclerlistview copied to clipboard
dataProvider not updating in layoutProvider when using Next JS / SSR
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.
Any help understanding this would be greatly appreciated and I can provide any other needed info.
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 did you find any workaround?
@callmemonky No, I'm still just using it in a class component which works.
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])
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 :)