use index in ItemSeperatorComponent - react-native

I am trying to use the current index in ItemSeparatorComponent as shown below, however index is always empty and never returns a value, but item is successfully populated. I'd really appreciate it if anyone can point out what I'm doing wrong here?
<FlatList
numColumns={1}
data={messages}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => <OFChatBubble message={item} />}
ItemSeparatorComponent={(item, index) => (
<DateSeparator item={item} index={index} />
)}
/>

To debug correctly you can try to add a debugger like this
ItemSeparatorComponent={(item, index) => {
debugger
return (
<DateSeparator item={item} index={index} />
)
}}
Open Chrome with the source tab opened to figure out the format of data={messages}

I'm pretty sure you just forgot the { }around the params in the arrow function you passed to ItemSeparatorComponent
The code should be:
ItemSeparatorComponent={({item, index}) => (
<DateSeparator item={item} index={index} />
)}
Edit:
I was wrong ItemSeparatorComponent does not get the same props as renderItem. It gets highlighted:boolean, leadingItem:<an object from the data you pass in> but you still need to use { } in order to get them

Related

How to use string methods inside FlatList react native

I need to use slice() method in my FlatList data but when I use it like below it doesn't work.
<FlatList data={userBookings} keyExtractor={item => item.id} renderItem={itemData => (
<Text style={styles.text}>{itemData.item.id.slice(3)}</Text>
.
.
.
)
}
/>
how can I solve this?
I think first mistake is not to use curly brackets for callback data.
Secondly you need to specify the first and last index for the .slice method
You can find the answer down below.
<FlatList
data={userBookings}
keyExtractor={item => item.id}
renderItem={({itemData,index}) => (
<Text style={styles.text}
{itemData.item.id.slice(0,3)}
</Text>
)}
/>

Prevent FlatList scrolling when new items are added

I have inverted vertical FlatList in my chat app, which shows newest message in bottom and oldest message in top (likes all other chat applications)
The problem is when I want to add new messages to bottom of my list, FlatList automatically jump to bottom-end of the list!
All I need is to prevent scrolling in this situation
Here is my FlatList:
<FlatList
inverted
style={{flex: 1}}
data={this.state.data}
keyExtractor={(item, index) => item.id}
renderItem={this.renderItem}
/>
And here is the code to add newest messages to list
const data = [ ...newMessages, ...this.state.data ];
this.setState({ data });
Your case look simple but you are adding new message at top then reverse it to bottom last position using inverted flag
Could remove inverted flag and add new item at last simply const data = [...this.state.data, ...newMessages];
<FlatList
style={{flex: 1}}
data={this.state.data}
keyExtractor={(item, index) => item.id}
renderItem={this.renderItem}
/>
const data = [...this.state.data, ...newMessages];
this.setState({ data });
I hope this will work
Put this in the view
<FlatList
data={this.state.data}
ref={ref => {
this.flatListRef = ref;
}}
initialScrollIndex={0}
keyExtractor={item => item.id}
extraData={this.state.refresh}
renderItem={({item, index}) => {
// animation={animation}
return (
<ListItem
inAnimation={inAnimation}
outAnimation={outAnimation}
duration={duration}
easing={easing}
isDeleted={item._isDeleted}
id={item.id}
item={item}
/>
);
}}
`/>`
Run this in a function
this.flatListRef.scrollToIndex({
animated: true,
index: nextProps.indexScroll})
});
You should use a workaround to achieve this. If you check the documentation for FlatList (which extends the props of ScrollView), you'll see that all you need to do is set the scrollEnabled prop to false to disable scrolling. How and where you choose to do this will be up to you since you didn't really post a lot of code. A simple way to handle this would be to use state:
<FlatList
...
scrollEnabled={this.state.scrollEnabled}
/>
In your case you could change the state when the new data is being loaded and change it back when it is rendered.
There is an open issue on Github about this case.

Algolia and React Native FlatList ListHeaderComponent

I you put an Algolia connected component in a header of a FlatList it's as if it enters an infinite loop of queries. The connectInfiniteHits runs constantly.
This is really annoying if you like to put some simple filters in the headers of a list of hits.
My setup is like this:
I have a FlatList that is wrapped by the connectInfiniteHits HOC.
The ListHeaderComponent contains a component this is wrapped by the connectRefinementList HOC. The same problem occurs with a connectSearchBox HOC.
Has anyone seen this and found a solution?
I manage to make it work with those lines:
const RefinementList = connectRefinementList(({ items, refine }) => (
<View>
{items.map(item => (
<TouchableOpacity key={item.label} onPress={() => refine(item.value)}>
<Text style={{ fontWeight: item.isRefined ? '600' : 'normal' }}>
{item.label}
</Text>
</TouchableOpacity>
))}
</View>
));
const InfiniteHits = connectInfiniteHits(({ hits, hasMore, refine }) => (
<FlatList
data={hits}
keyExtractor={item => item.objectID}
onEndReached={() => hasMore && refine()}
ListHeaderComponent={<RefinementList attribute="brand" />}
renderItem={({ item }) => (
<View>
<Text>{JSON.stringify(item).slice(0, 100)}</Text>
</View>
)}
/>
));
Note that I'm not using the function version which indeed breaks.

How do I render different data types from a fetched json?

I was using...
<FlatList
data={this.state.dataSource}
renderItem={({item}) => <Text>{item.username} {item.name}</Text>}
keyExtractor={({id}, index) => id}
/>
...to render two texts in React Native but now I've got an uri in my json...
How do I render the image in an IM style (thumbnail, username and name)?
Add a renderItem method and then put everything you need in there. Once you make the renderItem method you can throw it into your FlatList.
renderItem({ item }) {
return (
<View>
<Image
source={{uri: item.uri}}
/>
<Text>
{item.username}
</Text>
<Text>
{item.name}
</Text>
</View>
);
}
Then use the method inside the FlatList (the .bind makes sure it stays in the right context)
<FlatList
data={this.state.dataSource}
renderItem={this.renderItem.bind(this)}
keyExtractor={({id}, index) => id}
/>
You can build a component that takes your fields as its props, containing multiple Texts and an Image using your uri as the source. Style this like you would any other component, and then pass that component into renderItem.
You can embed the component immediately to the renderItem like this if the flatlist item is not complicated ( has a lot of component )
<FlatList
data={this.state.dataSource}
renderItem={({item}) => {
<View>
<Image source={{uri: item.uri.image}}/>
<Text>{item.userName}</Text>
<Text>{item.name}</Text>
</View>
}}
keyExtractor={(i) => i.toString()}
/>

Call this.props in function outside render gives undefine

Im having this problem with my flatlist. Basically im destructing my code to make it more readable. However my problem whenever I call the this.props outside the render it gives my undefine. Here's my code below:
renderItem(item) {
console.log(this.props) // Gives me undefine
return (
<ListItem button>
<Text>{item.item.name }</Text>
</ListItem>
)
}
render() {
return (
<FlatList
keyboardShouldPersistTaps={'always'}
data={countries.payload.data}
renderItem={this.renderItem}
keyExtractor={item => item.name}
/>
)
}
But if I did not separate to other function the renderItem. I can access the this.props:
render() {
return (
<FlatList
keyboardShouldPersistTaps={'always'}
data={countries.payload.data}
renderItem={({item, index}) => (
<ListItem button onPress={() => this.props.onPressAction()}> // I get the correct value
<Text>{item.name }</Text>
</ListItem>
)}
keyExtractor={item => item.name}
/>
)
}
When using react-native and ES6 classes it won't automatically bind your functions that is declared on your classes, so this will be a live object represent for the unknown context or even undefined which caused this.props to be undefined.
We need to handle the correct value of this to our methods on our own. Therefore either use:
Change to this.renderItem.bind(this)
Or use arrow functions like renderItem= () => {}