flipkart / recyclerlistview Goto Github PK
View Code? Open in Web Editor NEWHigh performance listview for React Native and web!
License: Apache License 2.0
High performance listview for React Native and web!
License: Apache License 2.0
Is there any reason why the _processOnEndReached is being called here? https://github.com/Flipkart/ReactEssentials/blob/78203c98ad1caf6ec379687dc3842d29b77f4148/src/core/RecyclerListView.js#L258
The onEndReached callback is always called before loading the first items, so if I wanna add some logic to add more items when reaching the end, like an infinite loading, it will be called even if it's not needed.
Is there any other reason to do that? Or maybe it could check if the dataProvided is not empty?
UPDATE: This only happens if forceNonDeterministicRendering = true
Everything gets fixed on doing even a minor scroll.
I've been experimenting with the new externalScrollView
prop trying to achieve a true sticky header experience. And this is what I came up with so far.
My solution was replacing the normal ScrollView
with an Animated.ScrollView
and have its onScroll
feed into an Animated value that I then use in the rowRenderer to stick some rows to the top.
This is my custom scrollview component.
class AnimatedScrollView extends React.Component {
render() {
return (
<Animated.ScrollView
ref={ref => (this._scrollView = ref)}
scrollEventThrottle={1}
{...this.props}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y:animatedScrollViewOffsetY } } }],
{
useNativeDriver: true,
listener: this.props.onScroll
}
)}
/>
);
}
}
I then use the animatedScrollViewOffsetY
Animated Value in the rowRenderer
and I calculate when the views should start sticking to the top like that:
const stickyConfiguration = {
startAt: 0,
duration: -1 * HEADER_HEIGHT
};
_.forEach(this.state.dataProvider._data, (row, rowIndex) => {
if (rowIndex < index) {
stickyConfiguration.startAt += this.getRowHeight(row.viewType);
} else {
if (rowIndex > index && row.viewType === ViewTypes.DAY_HEADER) {
return false;
} else {
stickyConfiguration.duration += this.getRowHeight(row.viewType);
}
}
});
I then pass the y:animatedScrollViewOffsetY
to my component which positions itself with some transforms:
const translateY = {
transform: [
{
translateY: this.props.animatedScrollViewOffsetY.interpolate({
inputRange: [
0,
stickyConfiguration.startAt,
stickyConfiguration.startAt + stickyConfiguration.duration
],
outputRange: [0, 0, stickyConfiguration.duration],
extrapolate: 'clamp'
})
}
]
};
One of the challenges I faced was with zIndex
values. I fixed it for iOS by changing the code for ViewRenderer
, but couldn't fix it on Android. There's also the problem with the onScroll
event that has to run both the Animated.Event
and do recyclerlistview
's logic as well. I couldn't get around that myself.
I unfortunately can't just fork recyclerlistview
and implement my solution since it doesn't work for Android yet, but that at least shows that the feature can be implemented. I'm thinking an additional property stickyViewTypes
or something like that.
Please let me know if you need more clarification on how I made that demo work. Would love to have this added to recyclerlistview soon! ๐
I am trying to add fixed footer how can I solve this problem
Relative to #71
A simple example, lets say we have a view that looks like this:
Image + TextAnd the Text is optional, while recycling if your component renders Text on the basis of whether text is there or not the Text component will see multiple unmounts/mounts. This might lead to drop in performance. A better way would be to simply hide Text (opacity = 0) and let it be there since it might get reused in future.
I want to know is there any difference between Opacity = 0
and Display = none
for hiding objects in recycle view
Is object with Display = none
recyclable? I turn on show layout bounds
and Display = none
has no bounds but Opacity = 0
has , So Is Display = none
has inconvenient unmounts/mounts
similar to renderScrollComponent
of FlatList
This happens when I first run the app on my device:
This is my component:
class EventList extends Component {
render() {
const { events, starredIds, starFn, unstarFn } = this.props;
let { width } = Dimensions.get("window");
let eventsAndStars = events.map(event => {
return { ...event, starred: _.includes(starredIds, event.id) };
});
let dataProvider = new DataProvider((r1, r2) => {
return r1 !== r2;
});
return h(RecyclerListView, {
dataProvider: dataProvider.cloneWithRows(eventsAndStars),
ref: "list",
onContentSizeChange: () => {
try {
this.refs.list.scrollToIndex(0);
} catch (e) {
console.log("scrolling to top went wrong: ", e);
}
},
style: styles.container,
layoutProvider: new LayoutProvider(
index => 0,
(type, dim) => {
dim.width = width;
dim.height = 90;
}
),
showsVerticalScrollIndicator: false,
rowRenderer: (type, event) => {
const {
id,
featured,
name,
description,
url,
startDate,
endDate
} = event;
const starred = _.includes(starredIds, event.id);
const now = new Date();
return h(EventRow, {
id,
name,
description,
url,
startDate,
endDate,
starred,
starFn,
unstarFn,
featured,
now
});
}
});
}
}
I'm using RN 0.47.2
Hi, following up on some conversations with @naqvitalha over in the react-native-web repo. Here are some findings/comparisons to our scroller from @madnl, who tried the component in Twitter Lite's timelines (on desktop Chrome):
A mechanism for saving position when coming back to timeline exists, but not sure how it is applied or if it works (see ContextProvider).
Sometimes items overlap
Although the following are not blocking issues since our current scroller does not have them either, it should be stated that this library does not seem to provide support for:
For the most part, it could work, although there is a point where it might not be generally usable for our timelines - given that timelines change in a non-linear way, there does not seem to be an anchoring mechanism that ensures the most visible item stays put when new items are rendered or removed above it. This would require identifying the items by key, instead of by index how it is now.
I've been trying to utilize both the onVisibleIndexesChanged
and initialRenderIndex
props at the same time, but I'm facing a weird behaviour that I'm not sure if it's intended to be that way.
When I provide an initialRenderIndex
value of 10, onVisibleIndexesChanged
is fired first with the values [0, 1, 2, 3, ...]
and then it's fired again with the correct values [9, 10, 11, 12, 13, ...]
I've reproduced in this snack https://snack.expo.io/ByBPIAtyM
Has it been implemented that way on purpose? And if so, what workaround would you guys suggest?
I have an issue as same as #60 but in both android and iOS (I think the problem is not depends on OS)
My rowRenderer
return an element connected to redux and I need to use redux , and I put dataProvider
in the mapStateToProps
Can you please provide an example that show how we can use this library with redux?
when set forceNonDeterministicRendering={true}, mistake in performance occurred :(, but i cannot set it to false; because layout will be damaged, any one can help??
this without forceNonDeterministicRendering but performance is high.
.
and this with forceNonDeterministicRendering, layout is awesome but performance is poor
any idea ??
Currently the library seems to export the source files as they are, without transpiling ES6 or JSX syntax down to more vanilla JS. This forces users of the library to match the assumed babel configuration this library expects.
Looks like the anchor logic is failing in cases where binary search is used.
please help me ...!
when wrap recyclerlistview with react-native-pull-to-refresh give me that error !, and cannot accept flex:1,any one can help ??
any way to refresh ??
Hi, I'm getting this warning error when loading the list on web
Warning: Unsupported vendor-prefixed style property webkitTransform. Did you mean WebkitTransform?
Check the render method of `ViewRenderer`.
The issue seems to be in this line https://github.com/Flipkart/ReactEssentials/blob/8e7df4a56f14e9dfb6584e9b0a397f81df5e43aa/src/recyclerlistview/viewrenderer/web/ViewRenderer.js#L64
when I scroll slowly it looks normal. But if I scroll quickly then the white screen appears but when the scroll stops displaying the item immediately.
It makes the users less comfortable. Is there any suggestion for this?
I have a case where some data in my Redux store is being updated, and I want the RecyclerListView to update its rows. Currently, if the row has been rendered it's not updated until I scroll far away and then scroll back. Is there a method that I can call to imperatively rerender the visible rows?
There is no documentation on what available props and methods.
Is there any method for navigating the list like scrollTo
, scrollToIndex
, scrollToItem
or a prop for setting initial list item to be focused?
From the documents, it looks like there is no RefreshControl support yet. Do you consider this lib as a drop in replacement of FlatList in the future?
Thanks.
You mentioned in document that "We built RecyclerListView which is a high performance list view written purely in JavaScript with staggered grid support."
Please provide instruction, How can I achieve staggered RecyclerListView .
I have a list of Events that users can star. However, whenever I star that event (and therefore add the event ID to starredIds
), the list snaps to the row nearest to the top. Is there a way to prevent this? It feels like bad UX.
class MyList extends Component {
render() {
const { events, starredIds, starFn, unstarFn } = this.props;
let { width } = Dimensions.get("window");
let eventsAndStars = events.map(event => {
return { ...event, starred: _.includes(starredIds, event.id) };
});
let dataProvider = new DataProvider((r1, r2) => {
return r1 !== r2;
});
return h(RecyclerListView, {
dataProvider: dataProvider.cloneWithRows(eventsAndStars),
ref: "list",
oncontentsizechange: () => {
try {
this.refs.list.scrolltoindex(0);
} catch (e) {
console.log("scrolling to top went wrong: ", e);
}
},
style: styles.container,
layoutProvider: new LayoutProvider(
index => 0,
(type, dim) => {
dim.width = width;
dim.height = 90;
}
),
showsVerticalScrollIndicator: false,
rowRenderer: (type, event) => {
const {
id,
name,
description,
} = event;
const starred = _.includes(starredIds, event.id);
const now = new Date();
return h(MyRow, {
id,
name,
description,
});
}
});
}
}
Thanks for cool library.
DataProvider supports only array as data source. I want to use it with Immutable.js data structures
ReactEssentials is exactly what I need. But I faced with this interesting situation when I tested with real data. I have a long list. But all list rendering with the same items (first 13 item).
Working fine on android but I stuck on ios.
recyclerlistview: ^1.1.4
react-native: 0.49.3
class UserList extends Component {
constructor(props){
super(props);
let dataProvider = new DataProvider((r1, r2) => {
return r1 !== r2;
});
let { width } = Dimensions.get("window");
this._layoutProvider = new LayoutProvider(
index => {
return ''
},
(type, dim) => {
dim.width = width;
dim.height = 84;
}
);
this.renderRow = this.renderRow.bind(this);
this.state = {
dataProvider: dataProvider.cloneWithRows(props.rows)
};
}
componentWillReceiveProps(nextProps){
let dataProvider = new DataProvider((r1, r2) => {
return r1 !== r2;
});
this.setState({ dataProvider: dataProvider.cloneWithRows(nextProps.rows)});
}
renderRow(type, { node }) {
return (
<UserRow user={ node } selectedAccount={this.props.selectedAccount} />
);
}
render(){
const { listKey } = this.props;
return (
<Content>
<RecyclerListView key={listKey} style={{width: 400, height: 400 }} layoutProvider={this._layoutProvider} dataProvider={this.state.dataProvider} rowRenderer={this.renderRow} />
</Content>
)
}
}
export default UserList;
On iOs and android we use "prepare for reuse" to make sure a view is ready to be reused.
The simplest example is Image
if there were an image already loaded and you set a new image that wont load (network error or such), you end with a view with the image for another cell.
Is there any way in your lib to set the image to "null" before it is reused?
Thanks
I'm getting wrong values from onVisibleIndexesChanged. It's returning an empty array sometimes.
I reproduced it in a snack.
https://snack.expo.io/@abdallamohamed/recyclerlistview-onvisibleindexeschanged-bug
You can see the bug when you're scrolling through the list.
When I call dataProvider.cloneWithRows()
and add more rows to the top of the list. The scroll position is lost. I tried investigating by reading the source code. I'd appreciate it if you could help with this!
And thanks for the great library! Its performance is amazing.
I'm trying to update the rows with cloneWithRows
, but looks like updating initialRenderIndex
at the same time as updating the dataProvider
doesn't actually work. Maybe that's the way it was intended to work, but I also noticed that the recyclerlistview
maintains scrollposition even if the overall height of it changes.
I made a quick snack of this case here: https://snack.expo.io/SJyh3xiyG
You can see that I have an initialRenderIndex
of 20, and there are 100 rows in total. Upon changing the rows to be 10, the scroll position hasn't changed and you'd have to scroll the recyclerlistview
a little bit and then the scroll position is fixed.
Changing the initialRenderIndex
doesn't have an effect as well, as I mentioned before.
If scrollToIndex is called on the ListView with let's say 5, the subsequent onVisibleIndexesChanged callback also has the value 4 in the all parameter. This might lead to problems in some cases like a calender etc.
I have a list with 10 different layout type , each type can text
comment or not , For example I have an Image
layout that can contain text
or not , layout here is similar to blog post
Another type is Video
that may contain text
or not
Must I define 20 different ViewTypes for LayoutProvider
?
I am using Recyclerlistview for my page, which is having first half with other functionality for site.
Then am using Recyclerlistview for data to render.
After integration the page scroll happens only to Recyclerlistview itself. And only 10% of Recyclerlistview are visible.
How to make my entire page to scroll to view my full Recyclerlistview.
How we can limit scroll speed?
Good day based on the source code I can see that there is an onSizeChange(), but I cannot find anything on how to change the size in such a mater that this event is triggered. Any pointers on what too look for?
I have a list with about 100 items . when I scroll I see blank area for 0.5 second
I try your sample with last version of react native
It has not same performance like your YouTube and I see blank area . I test at release mode in android 7 phone with 8 core CPU and 8 gig ram
Also in your sample except image all data is same and not changed so we have no cha he in view except images . If you try with better data and each row has different price and ... , the performance decreases and we have more blank area
I also increase renderAheadOffset
to 320 and 640 but still see blank area even in your sample project
When I rotate the device the cells are upgraded their size only when I scroll, and not on rotation. I've set the canChangeSize={true} props, the _layoutProvider is called once the device is rotated with the right new sizes, but the cell width is expanded or reduced only after some scrolling.
This is almost certainly not a bug in the RecyclerListView code (but might use a clarification in the documentation).
When I render my list, the first visible item in my list is at index 1 in my data provider. When I overscroll to the top (like a pull to refresh gesture), I can see my index 0 item being rendered in that position (off the top of the window). Am I missing styling?
I have a large data set contains different media and text
I can calculate all dimensions before rendering . except text
How can I exactly calculate text height for known width?? (I need a solution that works for web too)
Is the height depends on font-family too? Or just font-size?
First of all, thanks a lot for creating this great list view component. The built in FlatList and SectionList components of react-native are pretty bad at handling initial scrollOffsets, where this component really shines (especially with ContextProvider).
I found a bug where new props lead to exceptions through the componentWillReceiveProps call in RecyclerListView:
When the RecyclerListViews parent is re-rendered early after being mounted, the RecyclerListView's componentWillReceiveProps is called, but this.virtualizedRenderer is not yet initialized. This will lead to two exceptions in the following lines:
As a quick fix, I wrapped both lines in an if (this.virtualRenderer) { ... }
and there are no more exceptions or weird behavior.
You can try out the following sample to reproduce the bug:
I have a specific case here where there's a button that scrolls to a specific index in the list. If I tap the button when the list is idle, it scrolls there and renders things just fine, but if the user is already scrolling in the list, it scrolls to its destination and shows blank content until I start scrolling again.
As far as I understood from the source code, there's a render stack that's prepared and it's being updated on scroll. The problem is that as the user is scrolling, if I force the list to go to a specific index with no animation, the renderStack loses track of the items it should render, until I start scrolling again, and then the renderStack gets updated and it renders things correctly again.
I hope my explanation made sense. Please let me know if I need to elaborate further.
Hi,
I'm facing a problem that RecyclerListView cannot scroll if it's nested inside a ScrollView. It happens in Android, I haven't tested with iOs yet.
Do you have any idea about this problem?
Best regards,
Nghia.
I'm trying to change the content of the recylcerlistview
, but I keep getting Cannot read property 'reLayoutFromIndex' of undefined
. What could be causing that error?
I'm updating my data in the following way:
this.setState(prevState => ({
dataProvider: prevState.dataProvider.cloneWithRows(newRows)
}));
The error happens in RecyclerListView.js:224
in the line
this._virtualRenderer.getLayoutManager().reLayoutFromIndex(newProps.dataProvider._firstIndexToProcess, newProps.dataProvider.getSize());
That was called from componentWillReceiveProps
of RecyclerListView
in the line this._checkAndChangeLayouts(newProps);
_virtualRenderer
is getting set to null for some reason. Could you please explain what could be causing that problem
@naqvitalha I want to implement a simple version of sticky header for my use case
How can I detect that which item is topmost (or bottommost) and which is coming in view report and which is go out?
Hi!
The latest version has been released as version 1.0.7, the version before this was 1.0.61.
If your module is now installed via npm i --save, 1.0.61 is downloaded instead of 1.0.7. A quick fix would be to publish either a version above 1.0.61 or directly go for 1.1.0
I have an use case that LayoutProvider
must pass me item
to calculate dim.width
and dim.height
like the following code
this._layoutProvider = new LayoutProvider(
index => {
if (index % 3 === 0) {
return ViewTypes.FULL;
} else if (index % 3 === 1) {
return ViewTypes.HALF_LEFT;
} else {
return ViewTypes.HALF_RIGHT;
}
},
(type, dim , item) => {
dim.width = item.width();
dim.height = item.height();
}
);
(type, dim , item) => {}
OR (type, dim , index) => {}
is good
If I initially load a page before having data, returning an empty page(null/No Data) then fetch data from server after component mounted and set the data for data provider to my new data this error is produced at VirtualRenderer.getLayoutDimension.
On IOS it imediatly displays the "'getLayoutDimension' of undefined" error while on android the red screen displays 'Node has not been attached to a view' and the getLayoutDimension goes as a warning in background and on Debug console.
Commenting out the onEndReached property makes the problem stop.
I have tried to reproduce the error on snack/expo, but it does not reproduce the same error. On snack/expo it sometimes just work and other times expo just crashes.
Link to example: https://snack.expo.io/ryy4QxFRZ
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.