I Get the data from firebase real-time and put it I FlatList and when I delete if from Console "Firebase" it's deleted from the List in screen very well but the last item in the Array "Data" couldn't be deleted I don't know why!
I use an onRefresh Props but not help me because we all know the DB is real-time and when we will add any item it's will be in the last without refresh it So it's not work with the last item too and just the loading stuck without re-render the FlatList
Although I use .once('value') when I get data from DB, refresh work but when I refresh after deleting the last item the loading refresh stuck and can't disappear the last item
so how can I solve this issue?
here is my code
import auth from '#react-native-firebase/auth';
import database from '#react-native-firebase/database';
import React, {Component} from 'react';
import {
Dimensions,
FlatList,
Image,
Text,
TouchableOpacity,
View,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
const {width} = Dimensions.get('window');
export default class PendingOrders extends Component {
constructor(props) {
super(props);
this.state = {
orders: [],
forceUpdate: true,
isFetching: false,
};
}
onRefresh = () => {
this.setState({isFetching: true}, () => this.getApiData());
};
getApiData = () => {
try {
const uid = auth().currentUser.uid;
const Orders = database().ref(`usersOrders/${uid}`);
Orders.on('value', snapshot => {
let orders = [];
snapshot.forEach(childSnapshot => {
if (childSnapshot.val().status == 'pending') {
orders.push({
buildingNumber: childSnapshot.val().buildingNumber,
service: childSnapshot.val().categoryName,
date: childSnapshot.val().date,
time: childSnapshot.val().time,
description: childSnapshot.val().problemDescription,
status: childSnapshot.val().status,
images: childSnapshot.val().Images,
});
this.setState({orders, forceUpdate: false, isFetching: false}, () =>
console.log(this.state.orders),
);
return;
}
});
});
} catch (err) {
console.log('Error fetching data: ', err);
}
};
componentDidMount() {
this.getApiData();
}
_listEmptyComponent = () => {
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}>
<Image
style={{
width,
height: width * 0.7,
resizeMode: 'contain',
}}
source={require('../../assets/empty.png')}
/>
<Text
style={{
color: '#000',
marginVertical: 15,
textAlign: 'center',
fontSize: 20,
}}>
No item found
</Text>
</View>
);
};
render() {
console.log('is?', this.state.forceUpdate);
return (
<FlatList
showsVerticalScrollIndicator={false}
data={this.state.orders}
extraData={this.state.isFetching}
onRefresh={() => this.onRefresh()}
ListEmptyComponent={this._listEmptyComponent()}
refreshing={this.state.isFetching}
contentContainerStyle={{
flexBasis: '100%',
}}
renderItem={({item}) => {
return (
<TouchableOpacity
onPress={() =>
this.props.navigation.navigate('OrderDetailsScreen', {
service: item.service,
time: item.time,
date: item.date,
description: item.description,
images: item.images,
status: item.status,
})
}
style={{
margin: 15,
borderRadius: 10,
borderWidth: 1,
flexDirection: 'row',
borderColor: '#ddd',
}}>
<Image
style={{
borderRadius: 10,
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
width: 150,
height: 150,
}}
resizeMode="cover"
source={item.images[0]}
/>
<View
style={{
margin: 5,
marginLeft: 10,
justifyContent: 'space-evenly',
}}>
<Text
style={{
marginBottom: 5,
fontWeight: 'bold',
fontSize: 16,
marginTop: 5,
}}>
{item.service}
</Text>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
}}>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
// paddingHorizontal: 5,
}}>
<Icon name="date-range" color="#AEACAC" size={20} />
<Text style={{paddingHorizontal: 5}}>{item.date}</Text>
</View>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 5,
}}>
<Icon name="access-time" color="#AEACAC" size={20} />
<Text style={{paddingHorizontal: 5}}>{item.time}</Text>
</View>
</View>
<Text
numberOfLines={1}
ellipsizeMode="tail"
style={{marginBottom: 5, width: 160, marginTop: 5}}>
{item.description}
</Text>
</View>
</TouchableOpacity>
);
}}
keyExtractor={(item, index) => index.toString()}
/>
);
}
}
The key for re activating flatlist is extraData. just change it's value to something else and it will trigger flatlist re rendering. for simplicity pass a boolean value to extraData. every time you want to re active the flatlist, just toggle the value of extraData
Related
I need to make a screen like you see below in React Native
like that
I need to list this screen with this datalist I have
let denemeData = [
{
id: 1,
BestSellers: [
{
id: 1,
SellerName: 'Steril Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1254788325/photo/forget-sweet-try-home-sanitised-home.jpg?s=612x612&w=0&k=20&c=q6t80qrWvnWRln4PoxF8giI0hr9cNqdvFQiooFqIK3M=',
},
{
id: 2,
SellerName: 'Işıltı Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1218727916/photo/woman-wearing-gloves-cleaning-desktop.jpg?s=612x612&w=0&k=20&c=i0DvmRBBjo-Q4DaJHywi4mQzRYOCRjPKh3m7wIYHHNw=',
},
{
id: 3,
SellerName: 'Aybars Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1358089804/photo/beautiful-smiling-young-woman-cleaning-and-wiping-window-with-spray-bottle-and-rag-stock-photo.jpg?s=612x612&w=0&k=20&c=1OCBbZeIxBHAsrm6K7FTXgST91xb9TCaHYc74y1bq8s=',
},
{
id: 4,
SellerName: 'Hizmet Kolay',
imageUrl:
'https://media.gettyimages.com/id/1055221704/photo/young-woman-washing-window.jpg?s=612x612&w=0&k=20&c=Nd2TDn8pTRPe_bEkGec7ICNQ3pcoksMQWTCcGRVpfQI=',
},
{
id: 5,
SellerName: 'Aybars Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1358089804/photo/beautiful-smiling-young-woman-cleaning-and-wiping-window-with-spray-bottle-and-rag-stock-photo.jpg?s=612x612&w=0&k=20&c=1OCBbZeIxBHAsrm6K7FTXgST91xb9TCaHYc74y1bq8s=',
},
{
id: 6,
SellerName: 'Hizmet Kolay',
imageUrl:
'https://media.gettyimages.com/id/1055221704/photo/young-woman-washing-window.jpg?s=612x612&w=0&k=20&c=Nd2TDn8pTRPe_bEkGec7ICNQ3pcoksMQWTCcGRVpfQI=',
},
],
},
];`
I couldn't figure out how to list with FlatList as in the image because as it can be seen in the image, I need to make the first data large, the second and third data small and side by side, I tried to play with numColumns, I tried to play with numColumns, I tried to adjust the View manually, I couldn't do it in any way and my brain stopped, please guide me, I'm very tired and I can't do it, my brain stopped.
Thanks for ur helps
I tried giving numColumns value with FlatList, but I did not get the result I expected.;
<FlatList
bounces={false}
numColumns={2}
scrollEnabled={true}
data={sellers}
renderItem={({item}) => (
<Pressable
onPress={() => {
denemeFunc(item);
}}
style={{
height: 170,
width: '47%',
borderRadius: 10,
backgroundColor: 'red',
margin: 5,
}}>
<Image
style={{
height: '100%',
resizeMode: 'cover',
width: '100%',
borderRadius: 10,
position: 'absolute',
}}
source={{
uri: item.imageUrl,
}}
/>
<View
style={{
padding: 8,
justifyContent: 'flex-end',
alignItems: 'center',
height: '100%',
position: 'absolute',
}}>
<Text
style={{
color: 'white',
fontSize: 16,
fontFamily: 'Poppins-Bold',
textAlign: 'center',
}}>
{item.SellerName}
</Text>
</View>
</Pressable>
)}
showsVerticalScrollIndicator={false}
/>
as I can see in your layout, for the even lines you want a component with just one line and for odd lines you want a component with two images. So you can render different components according to the index of the list.
I think you can do something like this:
<FlatList
bounces={false}
numColumns={2}
scrollEnabled={true}
data={sellers}
renderItem={({item, index}) => (
if(index% 2 === 0){
// You render a component with just one line.
} else {
// You create the component with columns - A component with a
//flexDirection: 'row'...
}
)}
showsVerticalScrollIndicator={false}
/>
Hope this answer helps you :).
Use VirtualizedList for more flexibility and render items by row. Here is the simplified version.
Calculate row count based on the layout
Return array of items for a certain row based on the layout
Render items for the row
Optional: Add padding to the last item to compensate the partial row
const isOdd = (index) => index % 2 !== 0
// 1.
const getRowCount = (items) => items.length - Math.floor(items.length / 3)
// 2.
const getRow = (items, index) =>
isOdd(index)
? items.slice(index + (index / 2), index + (index / 2) + 2)
: [items[2 * index - index / 2]]
const requiresPadding = (items, index, row) =>
row.length == 1 && getRowCount(items) - 1 === index && isOdd(index)
...
<VirtualizedList
data={items}
getItemCount={getRowCount}
getItem={getRow}
renderItem={({ item: row, index }) => (
<View style={{ flexDirection: 'row' }}>
// 3.
{row.map((i) => <Item title={i.title}/>)}
// 4.
{requiresPadding(items, index, row) && <PaddingItem/>}
</View>
)}
keyExtractor={(row) => row[0].id}
/>
...
const Item = ({ title }) => (
<View style={{
flex: 1,
backgroundColor: '#eee',
height: 150,
justifyContent: 'center',
alignItems: 'center',
margin: 8,
}}>
<Text>{title}</Text>
</View>
);
const PaddingItem = () => (
<View style={{flex: 1, margin: 8}}/>
)
may be this will help you!
App.js
import React from 'react';
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
ImageBackground,
Text,
StatusBar,
} from 'react-native';
const DATA = [
{
id: 1,
SellerName: 'Steril Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1254788325/photo/forget-sweet-try-home-sanitised-home.jpg?s=612x612&w=0&k=20&c=q6t80qrWvnWRln4PoxF8giI0hr9cNqdvFQiooFqIK3M=',
},
{
id: 2,
SellerName: 'Işıltı Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1218727916/photo/woman-wearing-gloves-cleaning-desktop.jpg?s=612x612&w=0&k=20&c=i0DvmRBBjo-Q4DaJHywi4mQzRYOCRjPKh3m7wIYHHNw=',
},
{
id: 3,
SellerName: 'Aybars Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1358089804/photo/beautiful-smiling-young-woman-cleaning-and-wiping-window-with-spray-bottle-and-rag-stock-photo.jpg?s=612x612&w=0&k=20&c=1OCBbZeIxBHAsrm6K7FTXgST91xb9TCaHYc74y1bq8s=',
},
{
id: 4,
SellerName: 'Hizmet Kolay',
imageUrl:
'https://media.gettyimages.com/id/1055221704/photo/young-woman-washing-window.jpg?s=612x612&w=0&k=20&c=Nd2TDn8pTRPe_bEkGec7ICNQ3pcoksMQWTCcGRVpfQI=',
},
{
id: 5,
SellerName: 'Aybars Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1358089804/photo/beautiful-smiling-young-woman-cleaning-and-wiping-window-with-spray-bottle-and-rag-stock-photo.jpg?s=612x612&w=0&k=20&c=1OCBbZeIxBHAsrm6K7FTXgST91xb9TCaHYc74y1bq8s=',
},
{
id: 6,
SellerName: 'Hizmet Kolay',
imageUrl:
'https://media.gettyimages.com/id/1055221704/photo/young-woman-washing-window.jpg?s=612x612&w=0&k=20&c=Nd2TDn8pTRPe_bEkGec7ICNQ3pcoksMQWTCcGRVpfQI=',
},
];
const renderItem = ({ item }) => (
<>
<View>
{item.id == 1 && (
<View
style={{
margin: 10,
height: 120,
}}>
<ImageBackground
source={item.imageUrl}
style={{ width: '100%', height: '100%', borderRadius: 20 }}>
<Text style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
)}
{item.id == 2 ? (
<>
<View
style={{
flexDirection: 'row',
margin: 10,
height: 120,
width: 100,
justifyContent: 'space-between',
}}>
<View>
<ImageBackground
source={item.imageUrl}
style={{ width:150, height: '100%', borderRadius: 20 ,margin:5}}>
<Text
style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
<View>
<ImageBackground
source={item.imageUrl}
style={{ width:150, height: '100%', borderRadius: 20 ,margin:5}}>
<Text
style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
</View>
</>
) : null}
{item.id == 3 && (
<View
style={{
margin: 10,
height: 120,
}}>
<ImageBackground
source={item.imageUrl}
style={{ width: '100%', height: '100%', borderRadius: 20 }}>
<Text style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
)}
{item.id == 4 ? (
<>
<View
style={{
flexDirection: 'row',
margin: 10,
height: 120,
width: 100,
justifyContent: 'space-between',
}}>
<View>
<ImageBackground
source={item.imageUrl}
style={{ width:150, height: '100%', borderRadius: 20 ,margin:5}}>
<Text
style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
<View>
<ImageBackground
source={item.imageUrl}
style={{ width:150, height: '100%', borderRadius: 20 ,margin:5}}>
<Text
style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
</View>
</>
) : null}
</View>
</>
);
const App = () => {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
},
});
export default App;
here is output:
I am new in react native . i am get data from asynstorage. how to set that data from flatlist. my problem is can not set value properly in flatlist data. herewith below attached the JSon value and my code. am try to long time but no idea for that please help me. please
I get data to asystorage value Json Data
{
"users":[
{
"title":"Opna Women's Short Sleeve Moisture",
"image":"https://fakestoreapi.com/img/51eg55uWmdL._AC_UX679_.jpg",
"id":19
},
{
"title":"DANVOUY Womens T Shirt Casual Cotton Short",
"image":"https://fakestoreapi.com/img/61pHAEJ4NML._AC_UX679_.jpg",
"id":20
}
]
}
Main code.
import React, { useState } from 'react';
import { SafeAreaView, StyleSheet, View, Text, Image, Alert, TouchableOpacity } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';
import Icon from 'react-native-vector-icons/MaterialIcons';
import COLORS from '../../consts/colors';
import foods from '../../consts/foods';
import { PrimaryButton } from '../components/Button';
import AsyncStorage from '#react-native-async-storage/async-storage';
const CartScreen = ({ navigation }) => {
const [value, setvalue] = useState(true);
AsyncStorage.getItem('storeddata')
.then((value) => {
setvalue(value)
console.log("saveddata", value);
}
)
const CartCard = ({ item }) => {
console.log("itemlist", item);
return (
<View style={style.cartCard}>
<Image source={{ uri: item.image }} style={{ height: 80, width: 80 }} />
<View
style={{
height: 100,
marginLeft: 10,
paddingVertical: 20,
flex: 1,
}}>
<Text style={{ fontWeight: 'bold', fontSize: 16 }}>{item.title}</Text>
<Text style={{ fontSize: 13, color: COLORS.grey }}>
{item.title}
</Text>
<Text style={{ fontSize: 17, fontWeight: 'bold' }}>${item.id}</Text>
</View>
<View style={{ marginRight: 20, alignItems: 'center' }}>
<Text style={{ fontWeight: 'bold', fontSize: 18 }}>5</Text>
<View style={style.actionBtn}>
<Icon name="remove" size={25} color={COLORS.white} />
<Icon name="add" size={25} color={COLORS.white} />
</View>
</View>
</View>
);
};
return (
<SafeAreaView style={{ backgroundColor: COLORS.white, flex: 1 }}>
<View style={style.header}>
<Icon name="arrow-back-ios" size={28} onPress={navigation.goBack} />
<Text style={{ fontSize: 20, fontWeight: 'bold' }}>Cart</Text>
</View>
<FlatList
showsVerticalScrollIndicator={false}
contentContainerStyle={{ paddingBottom: 80 }}
data={value}
renderItem={({ item }) => <CartCard item={item} />}
ListFooterComponentStyle={{ paddingHorizontal: 20, marginTop: 20 }}
ListFooterComponent={() => (
<View>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
marginVertical: 15,
}}>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>
Total Price
</Text>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>$50</Text>
</View>
<View style={{ marginHorizontal: 30 }}>
<PrimaryButton title="CHECKOUT" onPress={() => navigation.navigate('Checkout')} />
</View>
</View>
)}
/>
</SafeAreaView>
);
};
const style = StyleSheet.create({
header: {
paddingVertical: 20,
flexDirection: 'row',
alignItems: 'center',
marginHorizontal: 20,
},
cartCard: {
height: 100,
elevation: 15,
borderRadius: 10,
backgroundColor: COLORS.white,
marginVertical: 10,
marginHorizontal: 20,
paddingHorizontal: 10,
flexDirection: 'row',
alignItems: 'center',
},
actionBtn: {
width: 80,
height: 30,
backgroundColor: COLORS.primary,
borderRadius: 30,
paddingHorizontal: 5,
flexDirection: 'row',
justifyContent: 'center',
alignContent: 'center',
},
});
export default CartScreen;
Flatlist data props take an array as an input Official doc
you are getting an object from local storage you have to pass an array to it
local storage save string value so you have to do JSON.stringify() it when you store data in it and JSON.parse() it when getting data from local storage
local storage link
If your value have that above JSON data stored then try to pass prop like:
<FlatList
...
data={value.users}
...
/>
Hope this works for you.
I'm using WordPress API in my react native app. Everything is working fine except my single post screen. I'm requesting post data, updating state, and rendering data from the state. My app was crashing after going on this screen. I spend hours and I've found out what's the problem however don't how to fix it.
My Screen Code -
import React, { useState, useEffect } from "react";
import {
ActivityIndicator,
Text,
View,
ScrollView,
Image,
useWindowDimensions,
} from "react-native";
import HTMLView from "react-native-htmlview";
import globalStyles from "../constant/globalStyle";
import axios from "axios";
import moment from "moment";
import { Colors } from "../constant/colors";
const PostDetail = ({ route }) => {
const { postId } = route.params;
const [postData, setPostData] = useState({});
const [loaded, setLoaded] = useState(false);
const [source, setSource] = useState("");
useEffect(() => {
const fetchData = async () => {
await axios
.get(
`https://bachrasouthpanchayat.in/wp-json/wp/v2/posts/${postId}?embed=true`
)
.then((response) => {
setPostData(response.data);
setSource(response.data.content.rendered);
setLoaded(true);
})
.catch((error) => console.log(error, error.message));
};
fetchData();
}, []);
const { width } = useWindowDimensions();
return (
<ScrollView
style={{
...globalStyles.container,
backgroundColor: Colors.BACKGROUND_SCREEN,
}}
>
{loaded ? (
<>
<Image
style={{
width: "100%",
height: 250,
}}
source={{ uri: postData.jetpack_featured_media_url }}
resizeMode="cover"
/>
<Text style={globalStyles.primaryHeading}>
{postData.title.rendered}
</Text>
<View style={{ paddingHorizontal: 18 }}>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 10,
}}
>
<Text
style={{
...globalStyles.date,
fontSize: 20,
fontWeight: "700",
}}
>
{moment(postData.date).format("LL")}
</Text>
</View>
<HTMLView
stylesheet={{
p: { fontSize: 20, color: "white", textAlign: "justify" },
h1: {
color: "white",
fontSize: 32,
},
h2: {
color: "white",
fontSize: 28,
},
figure: {
backgroundColor: "red",
width: "100% !important",
height: "100% !important",
},
img: {
width: "100% !important",
backgroundColor: "green",
},
}}
value={source}
imagesMaxWidth={width}
/>
</View>
</>
) : (
<View
style={{
alignItems: "center",
justifyContent: "center",
}}
>
<ActivityIndicator size={60} color={Colors.PRIMARY_GREEN} />
</View>
)}
</ScrollView>
);
};
export default PostDetail;
I've used a bunch of console log statements and found out that "when useEffect runs the request is sent to API but it didn't stay on that line of code to receive a response, instead remaining lines of codes are executed and that's why I was getting the undefined error". However, the state gets updated after some time but I still get the error.
I have used async & await but don't know why all those remaining lines of codes ran before getting a response.
When this page is rendered for the first time, your postData is an empty object:
const [postData, setPostData] = useState({});
and at this point of time you try to access it's children (but it doesn't have them yet):
<Text style={globalStyles.primaryHeading}>
{postData.title.rendered} // here you access the empty object
</Text>
Then the useEffect is called which populates that postData
The solution (just add the question mark after postData.title?.rendered):
<Text style={globalStyles.primaryHeading}>
{postData.title?.rendered}
</Text>
The better solution is to show loading until you have not fetched the component:
if(postData.title?.rendered)
return <ActivityIndicator size={24} color={"#424242"} />
return (
<ScrollView
style={{
...globalStyles.container,
backgroundColor: Colors.BACKGROUND_SCREEN,
}}
>
{loaded ? (
<>
<Image
style={{
width: "100%",
height: 250,
}}
source={{ uri: postData.jetpack_featured_media_url }}
resizeMode="cover"
/>
<Text style={globalStyles.primaryHeading}>
{postData.title.rendered}
</Text>
<View style={{ paddingHorizontal: 18 }}>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 10,
}}
>
<Text
style={{
...globalStyles.date,
fontSize: 20,
fontWeight: "700",
}}
>
{moment(postData.date).format("LL")}
</Text>
</View>
<HTMLView
stylesheet={{
p: { fontSize: 20, color: "white", textAlign: "justify" },
h1: {
color: "white",
fontSize: 32,
},
h2: {
color: "white",
fontSize: 28,
},
figure: {
backgroundColor: "red",
width: "100% !important",
height: "100% !important",
},
img: {
width: "100% !important",
backgroundColor: "green",
},
}}
value={source}
imagesMaxWidth={width}
/>
</View>
</>
) : (
<View
style={{
alignItems: "center",
justifyContent: "center",
}}
>
<ActivityIndicator size={60} color={Colors.PRIMARY_GREEN} />
</View>
)}
</ScrollView>
I am trying to build a react native application with the expo, First I try to build this application with my chrome web browser, it was worked without any issue after that I try to test the application with my android device and I'm getting an exception - "Text strings must be rendered within a <Text> component" HomeScreen.js files. I have no idea why this happened. My code as follows,
/*This is an Example of Grid View in React Native*/
// import * as React from "react";
import React from 'react';
import { Image, FlatList, StyleSheet, View, Text, TouchableOpacity, TextInput } from 'react-native';
import { COLORS } from '../../asserts/Colors/Colors';
import { CATEGORIES } from '../../asserts/mocks/itemListData';
import CategoryGridTitle from '../components/HomeGridTile';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import { HeaderButton } from '../components/HeaderButton';
import HomeScreenButton from '../components/HomeScreenButton';
//import all the components we will need
const renderTopBarItems = (topBarItems) => {
return (
<TouchableOpacity
style={styles.topBar}>
<Text style={styles.textStyle}> {topBarItems.item.category} </Text>
</TouchableOpacity>
)
}
const HomeScreen = props => {
const renderGridItem = (itemData) => {
return <CategoryGridTitle
title={itemData.item.title}
image={itemData.item.image}
onSelect={() => {
props.navigation.navigate({
routeName: 'PaymentHandlerScreen',
params: {
categoryId: itemData.item.id
}
});
}} />;
}
// const [images, setImages] = React.useState(picsumImages);
return (
<View style={styles.mainBody}>
<View style={styles.searchContainer}>
<TextInput
placeholder='Search'
style={styles.formField}
placeholderTextColor={'#888888'}
/>
<TouchableOpacity onPress={() => props.navigation.navigate('BarCodeScannerScreen')}
style={styles.saveFormField}>
<Image
source={require('../../../images/barcode.png')}
style={{
width: '100%',
height: '30%',
resizeMode: 'contain',
alignContent: 'center',
}}
/> </TouchableOpacity>
</View>
<View style={styles.tabBar}>
<FlatList
horizontal
pagingEnabled={true}
showsHorizontalScrollIndicator={false}
keyExtractor={(item, index) => item.id}
data={CATEGORIES}
renderItem={renderTopBarItems} />
</View>
<FlatList
keyExtractor={(item, index) => item.id}
data={CATEGORIES}
renderItem={renderGridItem}
numColumns={3} />
<HomeScreenButton style={styles.buttonView} />
</View>
);
};
HomeScreen.navigationOptions = navigationData => {
return {
headerTitle: 'Tickets',
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title='profile'
iconName='ios-star'
onPress={() => {
console.log('profile clicked');
}} />
<Item
title='more'
iconName='md-more'
onPress={() => {
console.log('more clicked');
}} />
</HeaderButtons>
)
};
};
export default HomeScreen;
const styles = StyleSheet.create({
mainBody: {
flex: 1,
justifyContent: 'center',
backgroundColor: COLORS.background,
paddingTop: '3%',
},
searchContainer: {
flex: 1,
flexDirection: 'row',
},
tabBar: {
paddingBottom: '3%',
},
topBar: {
width: 150,
borderWidth: 1,
borderRadius: 20,
borderColor: COLORS.primary_blue,
padding: '5%',
marginLeft: '5%',
},
textStyle: {
color: COLORS.primary_blue,
textAlign: 'center',
fontWeight: 'bold',
fontSize: 14,
},
formField: {
flex: 4,
borderWidth: 1,
padding: '4%',
marginLeft: '2%',
borderRadius: 10,
borderColor: COLORS.gray,
backgroundColor: COLORS.gray,
fontSize: 15,
height: '35%',
},
saveFormField: {
flex: 0.5,
justifyContent: 'space-between',
alignItems: 'center',
margin: 10,
},
buttonView: {
position: 'absolute',
bottom: 0,
left: 0,
},
});
Thank you.
I ran into this error a couple of times. RN doesn't like extra spaces in tags. try removing the spaces before and after {topBarItems.item.category}
<Text style={styles.textStyle}>{topBarItems.item.category}</Text>
I am trying to use the React Native FlatList to loop thru a fetch API response for a news page that will load from a modal that contains a web view element. Everything seems to work fine, but every time I click the news article, it always loop thru all of them and give me the last article instead of the clicked article. If I console.log(item.title) it returns the clicked article title, but does not load it. I even passed the article data as a state but I am not sure what I am doing wrong, please help. Please ignore the extra code since I am focus on making sure it works properly before refactoring and removing the unused CSS. Here is the code. Let me know if you need a repo to post the link. Thanks in advance.
import React, { Component } from "react";
import { WebView } from "react-native-webview";
import {
View,
StyleSheet,
Text,
ActivityIndicator,
Image,
Button,
Linking,
TouchableOpacity,
Modal
} from "react-native";
import { FlatList } from "react-native-gesture-handler";
export default class NewsPage extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: [],
isLoading: true,
modalVisible: false
};
}
componentDidMount() {
return fetch(
"https://newsapi.org/v2/everything?q=empleos&language=es&apiKey=bc9471b0c90c4d1a8d41860292e59d6b"
)
.then(response => response.json())
.then(responseJson => {
this.setState(
{
isLoading: false,
dataSource: responseJson.articles
},
function() {}
);
})
.catch(error => {
console.error(error);
});
}
setModalVisible(articleData) {
this.setState({
modalVisible: true,
modalArticleData: articleData
});
}
closeModal = () => {
this.setState({
modalVisible: false,
modalArticleData: {}
});
};
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
);
}
return (
<View style={{ flex: 1, paddingTop: 20 }}>
<FlatList
data={this.state.dataSource}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<View style={styles.newsListContainer}>
<Image
style={styles.newsImage}
source={{
uri:
item.urlToImage != null
? item.urlToImage
: "../assets/icon.png"
}}
/>
<View style={styles.newsInfo}>
<Text numberOfLines={2} style={styles.newsTitle}>
{item.title}
</Text>
<Text numberOfLines={3} style={styles.newsDescription}>
{item.description}
</Text>
<Text>{item.author}</Text>
</View>
<View style={styles.newsLink}>
<Button
title="Leer"
onPress={() => {
console.log(item);
this.setModalVisible(item);
}}
// {Linking.openURL(item.url);}}
/>
</View>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
>
<View style={styles.newsHeader}>
<TouchableOpacity
onPress={() => {
this.closeModal();
}}
>
<Text style={styles.newsClose}>Cerrar</Text>
</TouchableOpacity>
<Text>{item.title}</Text>
</View>
<WebView
startInLoadingState={true}
source={{ uri: item.url }}
style={{ padding: 8 }}
/>
</Modal>
</View>
)}
/>
</View>
);
}
}
NewsPage.navigationOptions = {
headerTitle: "Noticias en Español"
};
const styles = StyleSheet.create({
mainBackgroundColor: {
backgroundColor: "#007bff",
padding: 8
},
mainBackground: {
alignItems: "center",
justifyContent: "center",
flex: 1
},
textHeader: {
backgroundColor: "#fff",
marginTop: 16,
fontSize: 32,
padding: 8,
borderRadius: 8,
color: "#007bff"
},
firstText: {
fontSize: 16,
marginTop: 16,
marginBottom: 0,
color: "#fff"
},
phone: {
marginTop: 16,
color: "#fff"
},
secondText: {
fontSize: 16,
marginTop: 0,
color: "#fff"
},
thirdText: {
fontSize: 16,
marginTop: 8,
color: "#ffffff",
textTransform: "uppercase",
textAlign: "center",
padding: 8,
marginBottom: 12
},
firstButton: {
marginBottom: 16
},
newsListContainer: {
width: "100%",
marginBottom: 4,
padding: 4,
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between"
},
newsImage: {
flexBasis: "25%",
height: "100%"
},
newsInfo: {
flexBasis: "55%",
padding: 2,
alignSelf: "flex-start"
},
newsLink: {
flexBasis: "20%"
},
newsTitle: {
fontSize: 20,
color: "#000000",
marginLeft: 8
},
newsDescription: {
fontSize: 12,
color: "efefef",
marginLeft: 8
},
newsHeader: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
padding: 4
},
newsClose: {
fontSize: 20,
color: "red"
}
});
In your Modal, you are using
<Text>{item.title}</Text>
instead of
<Text>{this.state.modalArticleData.title}</Text>
also for the WebView component do the same.
source={{ uri: this.state.modalArticleData.url }}
One More Thing:
import Flatlist from react-native instead of
react-native-gesture-handler