FlatList not rendering JSON Image - react-native

I just want to render a simple FlatList with images from JSON online data.
Here is my code.
Images are one Json Object
I get the images data
data.append("images", listing.images);
Then when I try to render them in the FlatList I only get this empty squares with the correct number of pictures for the current listing. What I"m doing wrong here?
<View style={{ height: 120 }}>
<FlatList
horizontal
showsHorizontalScrollIndicator={false}
data={listing.images}
renderItem={({ item, index }) => (
<Image
uri={item.images}
preview={{ uri: item.images }}
tint="dark"
style={{ width: 90, height: 110, borderWidth: 1 }}
/>
)}
/>
</View>
For the Image is use:
import { Image } from "react-native-expo-image-cache";

Related

backgroundImage React Native not working with flatlist not showing me the images

i need to show the images on my screen with the element flatlist
const renderItem = ({ item }) => (
<ImageBackground
source={{ uri: item.imageUrl }}
imageStyle={{
borderRadius: 6,
resizeMode: 'contain'
}}
/>
);
return (<FlatList data={coursesData} renderItem={renderItem} keyExtractor={(item) => item.id} />);
I see a few issues:
Why are you using ImageBackground instead of just Image? ImageBackground is intended for use as a background.
If the source of your image is a url you must specify an image height and width.
give Flatlist style={{ flex: 1 }}, this will allow it to take up all the space it needs.

Select and deselect multiple Items in flatlist performance issue

Displaying more than 200+ images in the flatlist and make the user to select or deselect by clicking an image. So, when the user is clicks a image, Need to show the check-circle icon on the image. Similarly, when the user is deselect the selected image, need to remove the icon. I got two arrays images[] and selectedImagesId[]. Whenever the user selects an image, the image id will be pushed into selectedImagesId array. By the way, Iam showing the icon if the rendered image id avaliable in the selectedImagesId. The problem here is, it takes so long to display or remove the icon.
<FlatList
data={props.images}
extraData={selectedImagesId}
initialNumToRender={10}
refreshing={true}
removeClippedSubviews={true}
maxToRenderPerBatch={1}
windowSize={7}
showsVerticalScrollIndicator={false}
numColumns={3}
keyExtractor={(item) => item.id.toString()}
renderItem={(itemData) => <RenderData itemData={itemData} />}
>
const RenderData = ({ itemData }) => (
<View>
<TouchableOpacity
activeOpacity={0.8}
style={{
width: width / 3.5,
height: height / 7,
padding: 2,
}}
onPress={() => {
console.log('pressed');
if (props.selectedImages.includes(itemData.item.uri)) {
const index = props.selectedImages.indexOf(itemData.item.uri);
if (index > -1) {
props.removeImageandId(index, itemData.item.id);
}
} else {
props.selectImageandId(itemData.item.uri, itemData.item.id);
}
}}>
<Image
style={{ width: '100%', height: '100%' }}
source={{
uri: itemData.item.uri,
}}
/>
{selectedImagesId.includes(itemData.item.id) && (
<AntDesign
name='checkcircle'
size={24}
color='white'
style={{ position: 'absolute', bottom: 5, right: 15 }}
/>
)}
</TouchableOpacity>
<Text style={{ backgroundColor: 'red', fontSize: 25 }}>
{render.current++}
</Text>
</View>
);
You can Refer This article
It will guide you on how to render Only particular selected components that change.
not the Whole flatList components.
so, that based Only selected particular component you can remove the icon. not whole flatList Re-render.

React Native Flatlist image component flickers when data for the flatlist is resorted

I am actually trying to design a chat application, where i rendered all the chats using a flat lists and i have ordered the chats according to their recent message time in descending order, when the order of chat messages changes, the image in chat component gets flickered. Please suggest me a way to prevent this flickering ,in whatsapp and telegram flickering doesn't happen i want to have the smooth ui experience on my chat app also.
I used React Native for the front end.
Here is the Flat list code..
<FlatList
data={state.connections}
refreshing={state.loading}
onRefresh={fetchLatestData}
ListHeaderComponent={<Searchbar
key="editor"
placeholder="Search me..."
value={state.searchValue}
style={{ margin: 15, marginTop: 0 }}
onChangeText={(value) => { fetchConnections(value) }}
/>}
ListHeaderComponentStyle={{ width: width * 1 }}
renderItem={({ item }) => {
let doc_id = getDocId(item.uid, state.userData.uid)
return <ChatCardComponent key={item.uid} data={item} navigation={navigation} userData={state.userData} latestMessageData={state.chattedFriends.get(doc_id)} />
}}
keyExtractor={(item, id) => item.uid}
/>
ChatCardComponentCode is,
I have used react-native-expo-cached-image for Image component
const uri = data.photoUrl;
return (
<View style={styles.container}>
<TouchableOpacity key={data.uid} onPress={() => { props.navigation.navigate('chatWindow', { data: data, userData: userData }) }}>
<View style={styles.chatContainer}>
<CachedImage
style={{ width: 80, height: 80, borderRadius: 60 }}
source={{ uri: uri }}
/>
</View>
</TouchableOpacity>
</View>
Please suggest me fix for this issue.

Add one last element to the end of FlatList

I am trying to achieve the following, whereas all but the last are normal images coming from an array.
Currently this is the code for the FlatList:
<FlatList
data={images}
numColumns={3}
// ListFooterComponent={
// <View style={[StyleSheet.actionUploadedPictureFrame , {height: PIC_HEIGHT, width: PIC_WIDTH}]}>
// <Image source={require('../../../images/add-icon.png')} />
// </View>}
renderItem={ ({item, index}) => index == images.length -1 ?
<View style={{flexDirection: 'row'}}>
<Image style={[StyleSheet.actionUploadedPictureFrame , {height: PIC_HEIGHT, width: PIC_WIDTH}]} source={{uri: item.url}} />
<View style={[StyleSheet.actionUploadedPictureFrame , {height: PIC_HEIGHT, width: PIC_WIDTH}]}>
<Image source={require('../../../images/add-icon.png')} />
</View>
</View>
: <Image style={[StyleSheet.actionUploadedPictureFrame , {height: PIC_HEIGHT, width: PIC_WIDTH}]} source={{uri: item.url}} /> }
keyExtractor={(item, index) => index.toString()}
/>
Which long story short, renders the pictures in the array in a table of 3 columns, and checks for the last picture in the list and in addition to rendering the picture, it also renders this plus sign.
However this is bound to have some sort of error if the list has a number of elements multiple of 3, since the plus sign would most likely be out of the screen.
If I use ListFooterComponent, it renders it in an entirely new line.
Does anyone know an effective work around to this?
Since I don't think I was clear enough, I'll try to explain properly my idea with this sample code:
<FlatList
data={[...images, { plusImage: true }]}
numColumns={3}
renderItem={({ item }) => {
if (item.plusImage) {
return (
<View
style={[
StyleSheet.actionUploadedPictureFrame,
{ height: PIC_HEIGHT, width: PIC_WIDTH }
]}
>
<Image source={require("../../../images/add-icon.png")} />
</View>
);
}
return (
<Image
style={[
StyleSheet.actionUploadedPictureFrame,
{ height: PIC_HEIGHT, width: PIC_WIDTH }
]}
source={{ uri: item.url }}
/>
);
}}
keyExtractor={(item, index) => index.toString()}
/>;
I don't know if it's the best practice to concat data array like that directly in the data prop, but you can always choose to declare it earlier in the render method.
Let me know if this can fit your request.
I also came around the same situation and found a good way when I have check the documentation of FlatList so the best way that I recommend is to use ListFooterComponent you can pass a style object for that element using ListFooterComponentStyle Click here for more details.

React Native FlatList last item visibility issue

I am fetching products list and then displaying using a FlatList, my list contains 5 items and as you can see FlatList row height is variable because of varying description text. So the issue is my last item card is not completely visible maybe this is some kind of flat list issue or layout issue. Any help would be highly appreciated
renderProducts() {
if (this.props.loading === true) {
return (
<View style={Styles.spinnerStyle}>
<ActivityIndicator size='large' />
</View>
);
}
return (
<FlatList
data={this.props.myProducts}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<Card
title={item.title}
image={{
uri: item.image !== null ? item.image.src :'../resImage.jpg'
}}
>
<Text style={{ marginBottom: 10 }}>
{item.body_html}
</Text>
<Button
icon={{ name: 'code' }}
backgroundColor='#03A9F4'
fontFamily='Lato'
buttonStyle={{ borderRadius: 0, marginLeft: 0, marginRight: 0, marginBottom: 0 }}
title='VIEW NOW'
/>
</Card>
)}
/>
);
}
render() {
return (
<View>
<View style={Styles.viewStyle}>
<Text style {Styles.textStyle}>ProductsList</Text>
</View>
{
this.renderProducts()
}
</View>
);
}
Set bottom padding to the <FlatList> content container:
<FlatList
contentContainerStyle={{ paddingBottom: 20 }}
/>
Add {flex: 1} to the View tag housing the Flatlist component.
In my case,
const App = () => {
return (
<Provider store={createStore(reducers)}>
<View style={{ flex: 1 }}>
<Header headerText={'My App'} />
<ScreenTabs /> // this is my content with FlatList
</View>
</Provider>
);
};
export default App;
Just wrap it in a view with flex:1
<ParentView style={{flex:1}
<View style={{flex:1}}>
// Your flatlist
<View>
</ParentView>
Also, note that the each parent of this "View" in which Flatlist is wrapped must also be a View with Flex of 1. Otherwise, that your flatlist wont be visible.
use contentContainerStyle props of FlatList
<FlatList contentContainerStyle={{ paddingBottom: 20}} />
Latest update:
react-navigation has a SafeAreaView with an option to not show that bottom area.
import { SafeAreaView } from 'react-navigation';
<SafeAreaView forceInset={{ bottom: 'never' }} />
Old response below:
You can't see your list with flex: 1 because flex: 1 will grow the component to the parent. If the parent doesn't have flex: 1, it won't stretch to its parent or the screen. Keep in mind, however, that flex: 1 with a SafeAreaView will cause the bottom safe area to show. This will look bad if your SafeAreaView backgroundColor is a different color from your list's back ground.
My old workaround was to add an item to the bottom of the array of items, but I'm still exploring how to scroll past/under the bottom safe area margin with a FlatList (which is how I found this post to begin with).
Update: Using ListFooterComponent you can create even a plain white "footer" with height and/or a margin
For example (I wouldn't directly copy and paste this if I were you... there's surely a better way to detect bezel-less iPhones, especially in 2019 when we have more than one)
ListFooterComponent={<View style={{ height: 0, marginBottom: 90 }}></View>}
This is how I would do it, using the iPhoneX's height for now. But it's not future-proof since the conditional will need to be updated every time a new iPhone with no bezels comes out:
ListFooterComponent={<View style={{ height: 0, marginBottom: noBezels ? 90 : 0 }}></View>}
Or you could just always have some spacing at the bottom, like a loading gif, a message... whatever.
UPDATE 2:
I found out about react-native-device-info which has a hasNotch() method. I find that useful for styling for iPhones with no bezels by combining hasNotch() with Platform.OS === 'ios'
You can try this solution
For Vertical FlatList:
<FlatList
ListFooterComponent={<View />}
ListFooterComponentStyle={{height:200}}
/>
For Horizontal FlatList:
<FlatList
contentContainerStyle={{paddingRight:40}}
/>
For IOS issues you can apply some IOS specific props:
<FlatList
// ...
contentInset={{top: 0, bottom: 20, left: 0, right: 0}}
contentInsetAdjustmentBehavior="automatic"
// ...
/>
The solution with contentContainerStyle padding didn't seem the best overall for fixing the safe area IOS issues in my case.
Work very well for me
<FlatList
data={data}
contentContainerStyle={{ paddingBottom: 30 }}
style={{height: '95%'}}
renderItem={({ item, index }) => (
<ListItem item={item} onPress={() => handlePress(item, index)} />
)}
/>
Make use of the contentContainerStyle prop in the flatlist
<FlatList contentContainerStyle={{paddingBottom: 10}} />
For dynamic flatlist, you can assign height to the parent view. I resolved it with same.
<View style={{height:'80%'}}>
<Flatlist
extraData={data}
data={data}
renderItem={renderItem}
/>
</View>
I had the same issue and found the solution. To fix the issue just add style={{flex: 1}} for each View element who is a parent for FlatList.
See updated code below.
render() {
return (
<View style={{flex: 1}}> // Here you should add style as {flex: 1}
<View style={Styles.viewStyle}>
<Text style={Styles.textStyle}>ProductsList</Text>
</View>
{ this.renderProducts() }
</View>
);
}
This worked for me.
<View style={{flex: 1}}>
<FlatList
style={{flex: 1}}
data={data}
renderItem={({item}) => (
<ListItem item={item} onPress={() => handlePress(item)} />
)}
/>
</View>
#krish solution is great for the fixed-size list items, however as
#Neeraj Sewani said, it may not be suitable for dynamic size list items.
so you can fix the issue like this -in case direction is column -:
<View style={{height: '90%'}}>
<FlatList/>
</View>
Otherwise, -in case direction is row -:
<View style={{height: '90%', width:'90%'}}>
<FlatList/>
</View>
I was seeing this same problem in our Android + iOS React Native hybrid app. We embed the FlatList component within our native UIs inside a Fragment in Android and we were unable to scroll to the last item in the list, even though the scroll indicator would show that there was more to scroll, the ScrollView would simply not scroll further. I tried all the combinations of using a wrapping <View style={{flex:1}}> to wrap the FlatList as well as using contentContainerStyle={{flexGrow:1}} on the FlatList without success. Pursuing the clue further it turned out that the FlatList needs an absolute, predefined height on Android to allow scroll to the bottom - it works just fine on iOS but on Android using match_parent wasn't going to work. Since we need to support all types of devices, phone and tablet too, it wasn't possible to pre-define an absolute height either.
To fix this, I made a custom FrameLayout subclass to house the ReactRootView's fragment, which overrides onLayout() to ignore the child view measurements, forcing the views to have the exact dimensions of the FrameLayout, somewhat like so in Kotlin:
class StretchFrameLayout #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
for (child in children){
if (child.visibility == View.GONE) continue
child.updateLayoutParams {
this.width = measuredWidth
this.height = measuredHeight
}
if (needsRelayout){
handler.postDelayed({child.requestLayout()},1)
}
}
super.onLayout(changed, left, top, right, bottom)
}
}
This work very well in my case:
<FlatList
data={todos}
contentContainerStyle={{ height: '100%' }}
renderItem={({ item }) => <Todos items={item} pressed={pressed} />}
/>
I've solved it doing contentInset={{ bottom: data.length * itemStyle.height, }} with itemStyle.height being 50 worked fine.