React Native : uri rendered multiple times in flatlist - react-native

I'm a newbie to react native. I try to add a flatlist to my app.
I hava an array of datas designed like that:
["https://hi.com//image.png", //uri
"hello",
"https://hi.com//image2.png",
"welcome",
"https://hi.com//image3.png",
"great",
../..
]
Problem is that my image shows up but the text in the right side is actually my uri stringyfied.
I think there's something wrong with the keyExtractor:
renderItem =({item}) => {
return(
<View style ={{flex:1, flexDirection:'row'}}>
<Image source ={{uri: item}}/>
<View style ={{flex:1, justifyContent: 'center'}}>
<Text>{item}</Text>
</View>
</View>
)
}
render() {
return (
<View style={styles.mainContainer}>
<FlatList
data= {this.state.dataSource}
keyExtractor={(item,index) => index.toString()}
renderItem= {this.renderItem}
/>
</View>
);
}

your renderItem function loops thru every single element of array, not sure its the best option for your kind of data, maybe try to use something like this instead
const data = [{uri: 'https://link.io', text: 'hello'},{uri: 'http://anotherlink.co', text: 'bye'}]
then inside your renderItem fuction pass data:
<Image source ={{uri: item.uri}}/>
<Text>{item.text}</Text>
on the other hand if your you need to keep flat array, maybe be write some function with modulo of deviding index by 2 and from there get what goes where, but not sure why would you need that apart maybe from codewars challange ;)
good luck, hope this helps

your flatlist render item is trying to access the item in a loop.so everytime it gets looped,you are passing item to Image and item to Text.As #wijuwiju suggested,that is the best way to implement it.try to maintain keys to your data.Then your flatlist will render properly.

Store Item Like this:
profilePicture: 'https://picsum.photos/200',
Set Image Source Like this:
<Image source={{uri:profilePicture}}/>

Related

Is there a FlatList-like View without the scrolling?

Basically, I have a list of items (with images) inside a single Card (custom component). Because the rendering of those items is slow, I wanted to use a FlatList to render them incrementally.
Unfortunately, I get the expected error
VirtualizedLists should never be nested inside plain ScrollViews ...
But I don't actually want to use a ScrollView inside the Card. I just want to render a few Items in a single Card, which should change its size to fit all the items.
Setting scrollEnabled={false} on the FlatList still shows the error above.
Using the ListHeaderComponent and ListFooterComponent props is not an option, because the content above and below should NOT be rendered inside the Card.
Here is a minimal example of what I mean:
const Comp = () => {
return (
<ScrollView contentInsetAdjustmentBehavior="automatic">
<Text>Header</Text>
<Card>
<FlatList
data={data}
renderItem={({ item }) => (
<Image source={{uri: item.localImageUrl}}/>
)}
keyExtractor={(item) => item.id}
scrollEnabled={false}
initialNumToRender={0}
maxToRenderPerBatch={3}
contentInsetAdjustmentBehavior='automatic'
/>
</Card>
<Text>Footer</Text>
</ScrollView>
);
};
What's interesting though, that aside from the error - I get the result I expected, and I could technically hide that error and ignore it, but that does not seem like the recommended approach.
Important: I am not specifically looking for a FlatList solution. It could technically be any Component that renders items incrementally in a non-blocking way.
The important point with a Flatlist is the reusing of cells so that not all components need to be rendered at the same time. So scrolling is an important part of this. On the other hand two scrollable components inside eachother will make it impossible for the system to know which component should be scrolled.
If there are only 3 items and it should not be scrollable you can just include a list of items inside the Scrollview like this:
const Comp = () => {
return (
<ScrollView contentInsetAdjustmentBehavior="automatic">
<Text>Header</Text>
<Card>
{ data.map((item, index) => {
return (
<Text key={index}>{item.title}</Text>
);
}) }
</Card>
<Text>Footer</Text>
</ScrollView>
);
};

React Native FlatList performance improvements

I'm reading barcodes and every barcode I read I add to an array and show in flatlist. but after 30 barcodes adding to the array getting slow. is there any solution I can do?
renderItem:
const renderItem = useCallback(
({item, index}) => (
<View style={styles.ListItemContainer}>
<Text>
-{item} index: {index}
</Text>
<TouchableOpacity
onPress={() => {
setRemovedItem(index);
setShowAlert(true);
}}>
<Text style={{fontSize: 20, fontWeight: 'bold'}}>X</Text>
</TouchableOpacity>
</View>
),
[],
);
FlatList component:
<FlatList
renderItem={renderItem}
data={barcodeArray}
style={styles.ListContainer}
keyboardShouldPersistTaps="handled"
initialNumToRender={12}
removeClippedSubviews
windowSize={12}
maxToRenderPerBatch={12}
/>
adding barcode:
const readBarcode = barcode => {
setbarcodeArray([barcode, ...barcodeArray]);
setbarcodeValue('');
setkey(key + 1);
};
for this solution you can use VirtualizedList instead Flatlist . In general, this should only really be used if you need more flexibility than FlatList .
for more info see this
Did you try using this: https://github.com/Flipkart/recyclerlistview library. It renders far fewer items than FlatList and then recycles them. Should be must faster and more performant than the native flatlist. If this does not work then try to use getItemLayout in flatlist if you have a fixed height of the content.

ERROR - VirtualizedLists should never be nested inside plain ScrollViews with the same orientation

I'm working on a react-native app and I have to put a list of object in a Scrollview, so I use the FlatList component to do it. This is the piece of code that generates the error:
<ScrollView contentContainerStyle={style}>
Other components
<FlatList
style={style}
data={data}
scrollEnabled={false}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index}) => (somethings)}
/>
Other components
</ScrollView>
The complete error is: VirtualizedLists should never be nested inside plain ScrollViews with the same orientation because it can break windowing and other functionality - use another VirtualizedList-backed container instead.
Avoid using FlatList with the same orientation. Instead, restructure your code like this --
<ScrollView contentContainerStyle={style}>
Other components
{
data.map((item)=> <Somthing item={item}/>)
}
Other components
</ScrollView>
Flatlist has its own ScrollView you can scroll through the list using that so there is no need to put a flatlist into a ScrollView that is why its giving a warning, the both scrollview will clash and one of them (mostly the parent one) works.
The error is self explanatory and it should be in a developers best interest to avoid these kind of things even when it's just a false alarm.
Your particular situation could use the following solution:
<FlatList
data={data}
keyExtractor={(item, index) => `key-${index}`}
ListHeaderComponent={() => (
<SomeComponents>
...Some components those need to be on top of the list
</SomeComponents>
)}
ListFooterComponent={() => (
<SomeComponents>
...Some components those need to be below the list
</SomeComponents>
)}
renderItem={({ item, index}) => (somethings)}
/>
Another note, if you need more complex list that needs header and footer for the list itself, you can try SectionList.
Your component FlatList and ScrollView have the same orientation(vertical), so you need put your component inside a ScrollView with horizontal orientation like this:
<View>
<ScrollView nestedScrollEnabled={true} style={{ width: "100%" }} >
<View>
<ScrollView horizontal={true} style={{ width: "100%" }}>
<FlatList />
</ScrollView>
</View>
</ScrollView>
</View>
Solution 1: Use FlatList props ListHeaderComponent and create all of your page top section in that. Something like this:
This will not show any warning or error.
Solution 2:
Because only parent view will scroll (ScrollView) and not the child FlatList, so to get rid of the warning you can pass a prop scrollEnabled={false} to the FlatList.
If it doesn't go then import LogBox from react-native and write this in your component
useEffect(() => {
LogBox.ignoreLogs(["VirtualizedLists should never be nested"])
}, [])
hopefully, the warning will be removed.
Anyone want to solve this issue can use a custom VirtualizedScrollView like this:
import React from 'react';
import { FlatList } from 'react-native';
const VirtualizedScrollView = props => {
return (
<FlatList
{...props}
data={[]}
keyExtractor={(e, i) => 'dom' + i.toString()}
ListEmptyComponent={null}
renderItem={null}
ListHeaderComponent={() => (
<>{props.children}</>
)}
/>
);
};
export default VirtualizedScrollView;
Then if you use FlatList inside VirtualizedScrollView, it won't get the warning/error.
<VirtualizedScrollView>
<FlatList
/*--- your props ---*/
/>
</VirtualizedScrollView>
There is a npm package where I get this code, you can also use this package
Solution:
I have also encountered same problem with FlatList. Then the package below solved my problem.
'react-native-virtualized-view'
import { ScrollView } from 'react-native-virtualized-view'
if ScrollView is Vertical change Flatlist Horizontal
<ScrollView >
<FlatList
horizontal
data={lenders}
keyExtractor={(_, index) => index}
renderItem={(item) => {
return <Text>item</Text>
}}
/>
You can solve the 2 vertical ones(I'm assuming their side by side, separated with a segemented control?) by using the same flat list and switching out the data when it's switched. If they're just two vertical flat list's one after another use the SectionList.
For the horizontal one you can try putting the Horizontal FlatList in the ListHeaderComponent of the vertical FlatList and see what happens. It can be janky if you use a vertical FlatList in a vertical scroll view but maybe with two different axis it might be ok. The other option is two only show a few items in the horizontal scrollview and have a "Show More".
The last option is too re design/rethink the page so it's not doing so much. On mobile less is more and developers/designers like to get in the mindset of porting desktop thinking onto mobile. Might be worth a shot.
I used the SectionList approach to solve this & wanted to post a code example because I found the Section data required by React Native to be clear but also quite prescriptive.
renderList = ({empty, posts}: {empty: boolean, posts: Array<Object>}) => (
<SectionList
sections={[
{type: 'MAP', data: [{}]}, // Static sections.
{type: 'PROFILE', data: [{}]},
{type: 'POSTS', data: posts} // Dynamic section data replaces the FlatList.
]}
keyExtractor={(item, index) => index}
renderItem={({item, section}) => {
switch (section.type) {
// Different components for each section type.
case 'MAP':
return <MapView />;
case 'PROFILE':
return <Profile />;
case 'POSTS':
return <Post item={item} />;
default:
return null;
}
}}
ItemSeparatorComponent={() => <Separator />}
ListFooterComponent={() => <>{empty && <EmptyList />}</>}
/>
);
What's nice is that the content feels logically quite separate, so you can add sections easily or have different dynamic data sources.
(If you're building a form & want better keyboard handling, you could also try a KeyboardAwareSectionList from react-native-keyboard-aware-scroll-view.)
Flatlist has an integrated scrollview itself, so you can resolve this error by removing ScrollView Component, And let just the Fatlist component
Error ? you are trying to render a FlatList component inside a scrollview component, this is what is throwing the warning.
solution Render the components using Flatlist's ListHeaderComponent={} prop, i.e in your flatlist add the prop as follows
const FlatList_Header = () => {
return (
<View style={{
height: 45,
width: "100%",
backgroundColor: "#00B8D4",
justifyContent: 'center',
alignItems: 'center'
}}
>
<Text style={{ fontSize: 24, color: 'white' }}> Sample FlatList Header </Text>
</View>
);
}
<FlatList
data={BirdsName}
renderItem={({ item }) => <ItemRender name={item.name} />}
keyExtractor={item => item.id}
ItemSeparatorComponent={ItemDivider}
**ListHeaderComponent={FlatList_Header}**
ListHeaderComponentStyle={{ borderBottomColor: 'red', borderBottomWidth: 2 }}
/>
Note the use of the ListHeaderComponent in the code above, that should supress the warning.
Use flatList like this ListHeaderComponent and ListFooterComponent:
<FlatList ListHeaderComponent={
<ScrollView
style={styles.yourstyle}
showsVerticalScrollIndicator={false}
>
<View style={styles.yourstyle}>
</View>
</ScrollView>
}
data={this.state.images}
renderItem={({ item, index }) => {
return (
<View
style={styles.yourstyle}
>
<Image
source={{
uri: item,
}}
style={styles.yourstyle}
resizeMode={"contain"}
/>
<Text
numberOfLines={2}
ellipsizeMode="tail"
style={styles.yourstyle}
>
{item.name}
</Text>
</View>
);
}}
keyExtractor={({ name }, index) => index.toString()}
ListFooterComponent={
<View style={styles.yourstyle}></View>
}
/>
In my case it was happening due to nesting of ScrollView.
Try replacing some of the ScrollView from children components with React.Fragment.
The solution is very simple, please do not put the Flatlist component in the ScrollView.
They both have the same functionality but Flatlist has advantages and is more stable to use.

React-Native Flatlist not rendering when record is single

My React-Native Flatlist have refused render data when my json data is just one. My flatlist renders properly when the data on my Json is more than one.
I have tried all the ricks i can think of but yet, its not working.
This is happening to all the Flatlist in all my program and its sickining already.
I have tried getting the array side using Object.keys(jsonResponse.Product).length;
before choosing to either render to a Flatlist or return a single data View which refused to also work for me as the Object.key returns the same size when the data item is one and same when its two. (really strange)
I have also tried effecting the styling of the Flatlist my using
height:((Dimensions.get('screen').height)) and width:((Dimensions.get('screen').width))
in the Flatlist contentContainerStyle props, yet it does not render when data is single
Also tried using Array.from() to make sure that the data the flatlist will render is well converted to an object/array
I have also tried using this.state.PC_list_data.map() which still does not render when the data item is just one (single) like the flatlist
JSON OUTPUT WHEN DATA IS MORE THAN ONE
JSON SINGLE OUTPUT
render(){
return(<FlatList
contentContainerStyle={{
borderWidth: 0,
width:((Dimensions.get('screen').width)),
//height:((Dimensions.get('screen').height))+50,
borderColor:'#00d',
// marginTop:30
}}
data={ Array.from(this.state.PC_list_data) || []}
keyExtractor={(item) =>item.Product_id}
renderItem={({item,index})=>
{
return (<CategoryProduct_List
{...item}
List_index={index}
HrefNav={this.navigateToSubProduct.bind(this, {...item})}
/>
)}
}
/>)
}
///CODE ON THE CategoryProduct_List Component
const CategoryProduct_List = props =>
{
//alert('aaa')
return (<View style={[{
flex: 1,
display:'flex',
flexDirection: "row",
backgroundColor: 'rgb(243,243,243)',
marginHorizontal:10,
justifyContent:'space-between',
alignItem:'center',
borderLeftWidth:10,
borderLeftColor:'#80146D',
marginBottom:10,
marginLeft:5+'%',
marginTop:5,
padding:10,
width: 90+'%',
height:100+'%'
}]}>
<View style={{
alignItem:"left",
}}>
<TouchableOpacity
activeOpacity={0.7} onPress={()=> props.HrefNav()}>
<Text>{props.Product_name.toUpperCase()}</Text>
</TouchableOpacity>
</View>
<View style={{ alignItems: "flex-end",}}>
<TouchableOpacity
activeOpacity={0.7}>
<IconSet color='#80146D' onPress={()=> props.HrefNav()} size={25} name="arrow-forward"/>
</TouchableOpacity>
</View>
</View>);
}
export default CategoryProduct_List;
What i want to know is how i can make the Flatlist render my single records and what i am not doing right here
It may not be flatlist, since it works with one item ... it may be the data
Some API's return an array of json for multiple data Ex: [{1...},{2...},{3...}] and that is well received by the faltlist component. But when requesting only one item , the apis return an individual json Ex: {1...} , and faltlist only accepts an array of json, not an individual json...
For that you can use a validator function that will check if the data is array, or an individual json , and call it before using it as the flatlist data. it would help if you placed the response from both an item group, or an individual item
function format(data){
var result = []
if(!Array.isArray(data)){//if is not an array
result.push(data) // push it as the first item of an array
}else{
result=data
}
return result
}
can you post a sample of this.state.PC_list_data when you have 1 item and when you have multiple items please?
i also face this problem
Solution :
some time flatlist cant't be show single record you have to add extra data in flatlist
<FlatList
extraData={this.state} />
its work fine

How to Render only few elements in FlatList

I am having say about 100 elements in my array/object
I am using FlatList to display it
<FlatList
data={this.props.redditCryptoNews}
maxToRenderPerBatch={5}
renderItem={({index, item}) => {
return (
<Text style={RedditList}>{item["data"]["title"]}</Text>)}} />
Now, I just want to display just 10 elements in my flatlist instead of displaying all 100 elements
For some reason, I think Facebook haven't done good job with its react-native documentation which makes it sort of hard for me to comprehend
[Question:] How Can I achieve it?
Okay, It was stupid of me.
We can simply slice the data we are passing.
<FlatList
data={this.props.redditCryptoNews.slice(0,5)}
maxToRenderPerBatch={5}
renderItem={({index, item}) => {
return (
<Text style={RedditList}>{item["data"]["title"]}</Text>)}} />
Notice .slice(0,5) here
data={this.props.redditCryptoNews.slice(0,5)}