I'm using react native's FlatList to display a list of items, and also check which items are currently viewable. In my items there's one item which is marked mostUsed if the item is not viewable I display a link at the top, the user can click that and scroll to that item, using scrollToIndex. scrollToIndex works well without setting numColumns, when I set numColumns={2} I get scrollToIndex out of range: 9 vs 4 error.
setScrollIndex = () => {
if (this.state.scrollIndex !== 0) {
return;
}
for (let i = 0; i < this.state.items.length; i++) {
const items = this.state.items;
if (items[i] && items[i].mostUsed) {
this.setState({
scrollIndex: i,
});
}
}
};
// scroll to index function
scrollToIndex = () => {
this.flatListRef.scrollToIndex({
animated: true,
index: this.state.scrollIndex,
});
};
<FlatList
data={this.state.items}
numColumns={2}
keyExtractor={(item, index) => index.toString()}
ref={ref => {
this.flatListRef = ref;
}}
showsVerticalScrollIndicator={false}
onViewableItemsChanged={this.handleViewableItemsChanged}
viewabilityConfig={this.viewabilityConfig}
renderItem={({ item, index }) => (
<Card
title={item.title}
description={item.description}
mostUsed={item.mostUsed}
style={{ width: item.width }}
/>
)}
/>
expo snack
Looks like FlatList's scrollToIndex changes the way it views index if numColumns is higher then 1.
It may be more correct to call it scrollToRowIndex since it does not work on item index in case of multiple columns.
For your case this worked for me on expo:
scrollToIndex = () => {
this.flatListRef.scrollToIndex({
animated: true,
index: Math.floor(this.state.scrollIndex / numColumns),
});
};
Related
I am using sectionlist for showing data in react native.
I have large data with a section list.
Here We use scrolltolocation for scrolling to the specific section but it is not working until I render to that section using manual scroll
My Code:
<SectionList
sections={this.props.fooddata}
ref={(s) => (this.sectionList = s)}
//onScroll={this.handleScroll}
stickySectionHeadersEnabled={true}
onViewableItemsChanged={this.props.onCheckViewableItems}
viewabilityConfig={{
itemVisiblePercentThreshold: 50 //means if 50% of the item is visible
}}
removeClippedSubviews={false}
maxToRenderPerBatch={6}
scrollEnabled={true}
onScrollToIndexFailed={info => {
const wait = new Promise(resolve => setTimeout(resolve, 500));
wait.then(() => {
//flatList.current?.scrollToIndex({ index: info.index, animated: false });
});
}}
initialNumToRender={4}
windowSize={5}
ListFooterComponent={this.ItemSeprator}
style={{ width: this.windowwidth,top:this.props.searchclicked?135:(this.props.nonveg || this.props.veg)?200:117,bottom:0,position:'absolute'}}
// keyExtractor={(item, index) => index}
keyExtractor={this.keyExtractor}
renderSectionHeader={({ section,index }) => this.createSection(section,index)}
// renderItem={(item)=>this.jackRecommned(item)} //{({ item, index }) => this.renderItem(item, index)}
renderItem={this.renderItem.bind(this)}
renderFooter={this.footer}
/>
I'm using Flatlist and list items don't have specific height, when I want to scroll to a specific index it's not scrolling to an exact item, and takes a while to go to that item.
this is the video of the problem
when I use this.flatlist.scrollToindex(), I get the error flatlist.scrollToindex() is not a function so I use :
this.flatList.scrollToItem({
animated: true,
item: item,
viewPosition: 0.5,
});
this is the component which has a flatlist inside and doesn't have getItemLayout function:
<CustomFlatList
header={headerComponent}
inverted={renderAsChat || invertedList}
style={[
postStyles.dashboardContainer,
isLonelyPost && { backgroundColor: '#fff' },
]}
loading={loading}
onRefresh={customRefresh === true ? refresh : this.onRefresh}
content={content}
pageTabTitle={pageTabTitle}
renderItem={({ item, key, index }) =>
this.renderPostItem(item, index, pageTabTitle)
}
emptyMessage={emptyMessage}
keyExtractor={(item, key) => this.getItemKey(item)}
loadMore={customLoadMore === true ? loadMore : this.loadMore}
scrollState={this.state.sendPostButtonVisible}
changeScrollState={this.changeScrollState}
navigation={navigation}
onViewableItemsChanged={this.onVideoExitScreen}
enableLoadMore={enableLoadMore && !isLonelyPost}
yOffsetThreshold={1000}
ref={(ref) => { this.flatList = ref; }}
/> : <View />
I have a FlatList which renders numbers from 1-10 along with a radio button. If I have pre-selected number which could be dynamic, that numbered radio button is pre-selected. How to calculate the scrollToItem/scrollToIndex in this case ?
componentDidMount() {
this.scrollToItem();
}
scrollToItem = () => {
let dynamicIndex = dynamicIndex
//calcuate the dynamic Index
this.flatListRef.scrollToIndex({ animated: true, index: dynamicIndex });
};
<FlatList
ref={ref => {this.flatListRef = ref;}}
bounces={false}
keyExtractor={item => item.id}
data={listData}
renderItem={({ item, index })=>
this.renderItem(item,index)}
/>
But it throws error "Cannot read property 'scrollToIndex' of index. Basically it can't find 'this.flatListRef' during component mount.
I am trying to build a Chat Application using react-native and using flatlist to display the messages. And i want my list to stay at bottom always can anyone plzz suggest me a solution.
Basically you need to use scrollToEnd on flatList..
First: create a flatList reference with:
ref={ (ref) => { this.myFlatListRef = ref } }
Second: add onContentSizeChange listener on flatList
onContentSizeChange={ () => { this.myFlatListRef.scrollToEnd({animated:true}) } }
Third: add onLayout listener on flatList for scroll to bottom when keyboard is showed.
onLayout={ () => { this.myFlatListRef.scrollToEnd({animated:true}) } }
eg:
<FlatList
ref={ (ref) => { this.myFlatListRef = ref } }
onContentSizeChange={ () => { this.myFlatListRef.scrollToEnd({animated:true}) } }
onLayout={ () => { this.myFlatListRef.scrollToEnd({animated:true}) } }
data={this.state.messages}
renderItem={ ({item}) => <Item data={item} /> }
/>
the simplest way to do this is to use inverted props in the flatlist
this allow us to render list up-side-down
for more ref. vidit https://facebook.github.io/react-native/docs/flatlist#inverted
Here, you can do this -
const messageData = this.props.convo
return (
<View style={{ flex: 1 }}>
<FlatList
inverted={-1}
style={styles.list}
extraData={this.props}
data={messageData}
keyExtractor = {(item) => {
return item.id;
}}
renderItem=
{this.renderItem}
/>
after that, you will get an inverted list which will have the topmost elements in the list, so for fixing this you can add reverse() in your flatlist data or in your reducer. Like this-
data={messageData.reverse()} or in reducer return { ...state, chats: action.payload.reverse() }
You can give a refto FlatList and access certain flatList properties that can scroll at particular position. Here below resolution should work.
setTimeout(() => this.refs.flatList.scrollToEnd(), 200)
ScrollToEnd React native
I'm making a Chat app in React Native, in my app I have a Flatlist to show a message. When user pull the list, it will get new data and add to list. But the list will be re-render and scroll to start item. Is there anyway to make it still get data but stay in current position, like Facebook Messenger ?
I'm using FlatList like this :
<FlatList
refreshControl={
<RefreshControl
refreshing = {this.state.refreshing}
onRefresh = {this.addMessageToList}
/>
}
keyExtractor={(item, index) => index.toString()}
ref="flatList"
style={{ flex: 1 }}
data={newList}
renderItem={({ item, index }) => {
return (
<ChatContentItems item={item} index={index} parentFlatList={this}>
</ChatContentItems>
);
}}>
</FlatList>
Use onEndReached event to handle when user reached the end.
<FlatList
data={this.state.latestData}
keyExtractor={item => item.id.toString() }
renderItem={({item}) => <JobsListCell item={item}/>}
onEndReached={this.loadMore.bind(this)} // add this
onEndReachedThreshold={0.3} /> // and this. change according to your preference.
Since you have the full array with you, slice and append the next items to the latest array.
loadMore() {
let { latestData, fetchedData, incrementingAmount } = this.state;
if (latestData.length < fetchedData.length) {
this.setState({
latestData: [...latestData, ...fetchedData.slice(latestData.length, latestData.length + incrementingAmount)]
})
}
}
You can use scrollToEnd or scrollToItem after your addMessageToList completes
Also, ref strings are deprecated. You can use
ref={ (flatList) => this.flatList = flatList }