i'm working with my project using react native and firestore, i'm trying to get document from my collection 'requests' by uid that have the same uid with current logged in user and after retrieve it show the data but i got an error TypeError: docs.forEach is not a function. Previously i have successfully add the document to collection with current logged in user uid. Here is my code
constructor() {
this.state={
requests:[]
}
}
componentDidMount(){
this.fetchRequests();
}
fetchRequests(){
this.subscriber = firebase.firestore()
.collection("requests").doc(firebase.auth().currentUser.uid).onSnapshot(docs => {
let requests = []
docs.forEach(doc => {
requests.push(doc.data())
})
this.setState({requests})
})
}
buildPanels() {
if (this.state.requests.length !== 0) {
return this.state.requests.map((req, idx) => {
return <View key={idx} style={styles.panel}>
<View style={{flex: 1}}>
<View style={styles.panelRow}>
<Text style={styles.panelText}>Name</Text>
<Text style={styles.panelText}>{req.name}</Text>
</View>
<View style={styles.panelRow}>
<Text style={styles.panelText}>Blood Type</Text>
<Text style={{flex: 0.5}}>{req.golDarah}</Text>
</View>
<TouchableOpacity onPress={this.deleteData}>
<Text style={{color:color.red}}>End Request</Text>
</TouchableOpacity>
</View>
</View>
</View>
</View>
});
}
else{
return <View>
<Text style={{fontSize: fontSize.regular + 1, color: color.red}}>you dont have request</Text>
</View>
}
}
render(){
return(
{this.buildPanels()}
)
}
when you select firebase.firestore.collection('your collection').get() you're allowed use forEach because you will loop documents. Your question you get a 'Specific Document' so you don't have document to loop.
In your case
firestore()
.collection("requests")
.doc(firebase.auth().currentUser.uid)
.get()
.then(docs => {
if (docs.exists) {
console.log('requests data: ', docs.data());
}
});
Related
i have data from firebase and i want map it to my custom panels but it seems not mapped (my panels do not show up) but when i console log it, the data succesfully retreived. here is my code
constructor(props) {
super(props);
this.state ={
requests:[]
}
}
componentDidMount(){
this.fetchRequests();
}
fetchRequests(){
this.subscriber = firebase.firestore()
.collection("requests").onSnapshot(docs => {
let requests = []
docs.forEach(doc => {
requests.push(doc.data())
})
this.setState({requests})
})
}
buildPanels() {
this.state.requests.map((req, idx) => {
return <View key={idx} style={styles.panel}>
<View style={{flex: 1}}>
<View style={styles.panelRow}>
<Text style={styles.panelText}>Nama Resipien</Text>
<Text style={styles.panelText}>{req.name}</Text>
</View>
<View style={styles.panelRow}>
<Text style={styles.panelText}>Golongan Darah</Text>
<Text style={{flex: 0.5}}>{req.golDarah}</Text>
</View>
</View>
</View>
})
render(){
return(
<View style={styles.container}>
<ScrollView>
{this.buildPanels()}
</ScrollView>
</View>
);
}
Add return method in your code like
buildPanels() {
return this.state.requests.map((req, idx) => {
return <View key={idx} style={styles.panel}>
<View style={{flex: 1}}>
<View style={styles.panelRow}>
<Text style={styles.panelText}>Nama Resipien</Text>
<Text style={styles.panelText}>{req.name}</Text>
</View>
<View style={styles.panelRow}>
<Text style={styles.panelText}>Golongan Darah</Text>
<Text style={{flex: 0.5}}>{req.golDarah}</Text>
</View>
</View>
</View>
})
I fetched the data from api, I could show the data in console but it did not dispaly in the application.I tried many ways but it still undisplayed inthe app.
this is how I fetched the api.
const [dataProduct,setDataProduct] = useState([]);
useEffect(() => {
getProductsApi();
},[])
const getProductsApi = async () => {
axios.get(productUrl)
.then((res) => {
// console.log(res.data)
setDataProduct(res.data)
}).catch(err => console.log(err))
// const response = await fetch(productUrl);
// const data = await response.json();
// try{
// setDataProduct(data);
// dataProduct.forEach(pro => {
// return(console.log(pro.title.rendered));
// })
// }catch(err) {
// console.log(err)
// }
}
there is where I am using the data I tried to cossole the dataProduct variable at first it display an empty array after seconds it show the data of api but still not diisplay on application
return (
<SafeAreaView style={productsCaS.C}>
<View style={productsCaS.warp}>
<Text style={productsCaS.txt}>مواد غذائية</Text>
<ScrollView
onScroll={({ nativeEvent }) => change(nativeEvent)}
showsHorizontalScrollIndicator={false}
pagingEnabled
horizontal
style={productsCaS.box}
bouncesZoom={true}
>
{dataProduct.forEach((product) => {
return(
<View style={{ width: phoneH.W(45), marginRight: phoneH.W(2.5) }}>
<TouchableOpacity style={productsCaS.box}>
<Image
source={{ uri: 'https://huzurshops.com/wp-content/uploads/2013/06/3a-300x300.jpeg' }}
style={productsCaS.img}
/>
<Button
buttonStyle={productsCaS.btn}
containerStyle={productsCaS.btn}
icon={
<Ikon is={'SimpleLineIcons'} i={'handbag'} s={24} />
}
iconRight={true}
title='اضافة الى السلة'
titleStyle={productsCaS.btnTxt}
/>
</TouchableOpacity>
<TouchableOpacity style={productsCaS.title}>
<Text style={productsCaS.titleTxt}> {product.title.rendered}</Text>
</TouchableOpacity>
<View style={productsCaS.iconBox}>
<Ikon is={'Entypo'} i={'star'} s={20} c={'yellow'} />
<Ikon is={'Entypo'} i={'star'} s={20} c={'yellow'} />
<Ikon is={'Entypo'} i={'star'} s={20} c={'yellow'} />
<Ikon is={'Entypo'} i={'star'} s={20} c={'yellow'} />
</View>
<Text style={productsCaS.price}>{product._price}</Text>
</View>
)})}
</SafeAreaView>
</View>
I am not sure how to add a delete function in a FlatList. I know I can make different components, but I want to know how to do it within this one file. I've trying to figure this out for hours, but do not know how to do.
export default function test() {
const [enteredGoal, setEnteredGoal] = useState("");
const [courseGoals, setCourseGoals] = useState([]);
const goalInput = enteredText => {
setEnteredGoal(enteredText);
};
const addGoal = () => {
setCourseGoals(currentGoals => [
...currentGoals,
{ key: Math.random().toString(), value: enteredGoal }
]);
};
const removeGoal = goalId => {
setCourseGoals(currentGoals => {
return currentGoals.filter((goal) => goal.id !== goalId);
})
}
return (
<View style={styles.container}>
<View>
<TextInput
color="lime"
style={styles.placeholderStyle}
placeholder="Type here"
placeholderTextColor="lime"
onChangeText={goalInput}
value={enteredGoal}
/>
</View>
<FlatList
data={courseGoals}
renderItem={itemData => (
<View style={styles.listItem} >
<Text style={{ color: "lime" }}>{itemData.item.value}</Text>
</View>
)}
/>
<View>
<TouchableOpacity>
<Text style={styles.button} onPress={addGoal}>
Add
</Text>
</TouchableOpacity>
</View>
</View>
);
}
You just need to modify your code a bit to handle the delete button. Since you already have delete functionality, call that function when you click the delete button. That's it.
<FlatList
data={courseGoals}
renderItem={itemData => (
<View style={{ flexDirection: "row", justifyContent: "space-between" }}>
<Text style={{ color: "lime" }}>{itemData.item.value}</Text>
<TouchableOpacity onPress={() => removeGoal(itemData.item.key)}>
<Text>Delete</Text>
</TouchableOpacity>
</View>
)}
/>;
EDIT
change your removeGoal function as below
const removeGoal = goalId => {
setCourseGoals(courseGoals => {
return courseGoals.filter(goal => goal.key !== goalId);
});
};
Hope this helps you. Feel free for doubts.
I have a flat list, which gets its data source as a state. Actually, this data is from firebase, and i have been using redux. So, the data is fetched in the actions, and using callback i get the data to state.
What i want to achieve is, when there is no data found from the api, An empty list message should be show in the view. Actually , i achieved this using "ListEmptyComponent". But whats happening is the screen starts with empty message, and the spinner loads below it, and then if data found the message goes away as well as spinner.
But, what i wanted is, when the view gets rendered the first thing everyone should see is the spinner, and then if data empty spinner hides then empty list message displays.
How to achieve this ?
My Action :
export const fetchOrderHistory = (phone, callback) => {
return (dispatch) => {
dispatch({ type: START_SPINNER_ACTION_FOR_ORDER_HISTORY })
firebase.database().ref('orders/'+phone)
.on('value', snapshot => {
const snapShotValue = snapshot.val();
callback(snapShotValue);
dispatch ({ type: ORDER_HISTORY_FETCHED , payload: snapshot.val()});
dispatch({ type: STOP_SPINNER_ACTION_FRO_ORDER_HISTORY })
});
};
};
My Flat List & spinner:
<FlatList
data={this.state.historyOfOrders}
keyExtractor={item => item.uid}
ListEmptyComponent={this.onListEmpty()}
renderItem={({ item }) => (
<Card
containerStyle={{ borderRadius: 5 }}
>
<View style={styles.topContainerStyle}>
<View>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('ViewOrderScreen', {itemsOfOrder: item}) }
>
<View style={styles.viewOrderContainer}>
<View style={styles.viewOrderTextContainer}>
<Text style={styles.viewOrderTextStyle}>View Order</Text>
</View>
<Icon
name='ios-arrow-forward'
type='ionicon'
color='#ff7675'
/>
</View>
</TouchableOpacity>
</View>
</View>
</View>
</Card>
)}
/>
{this.props.isSpinnerLoading &&
<View style={styles.loading}>
<ActivityIndicator size="large" color="#03A9F4"/>
</View> }
My Call back at componentWillMount which set state:
componentWillMount() {
this.props.fetchOrderHistory((this.props.phone), (snapShotValue)=> {
const userOrderHistory = _.map(snapShotValue, (val,uid) => ({uid, ...val}))
this.setState({ historyOfOrders: userOrderHistory })
});
}
My EmptyList Message:
onListEmpty = () => {
return <View style={{ alignSelf: 'center' }}>
<Text style={{ fontWeight: 'bold', fontSize: 25 }}>No Data</Text>
</View>
}
My State:
state = { historyOfOrders: "" }
I am getting the spinner values from the reducers, using mapStateToProps.
Kindly Guide me, through
you have to do two things for that.
First, show Flatlist only if the loader is stopped. Second, set default value of this.state.historyOfOrders is null and check if this.state.historyOfOrders not null then only show Flatlist.
Here is a code:
{(!this.props.isSpinnerLoading && this.state.historyOfOrders != null) ?
(
<FlatList
data={this.state.historyOfOrders}
keyExtractor={item => item.uid}
ListEmptyComponent={this.onListEmpty()}
renderItem={({ item }) => (
<Card containerStyle={{ borderRadius: 5 }}>
<View style={styles.topContainerStyle}>
<View>
<TouchableOpacity onPress={() => this.props.navigation.navigate('ViewOrderScreen', {itemsOfOrder: item}) }>
<View style={styles.viewOrderContainer}>
<View style={styles.viewOrderTextContainer}>
<Text style={styles.viewOrderTextStyle}>View Order</Text>
</View>
<Icon
name='ios-arrow-forward'
type='ionicon'
color='#ff7675'
/>
</View>
</TouchableOpacity>
</View>
</View>
</Card>
)}
/>
) : null
}
With this condition, even if you want loader above Flatlist you can do that.
The path you should take is rendering only the spinner when the loading flag is set and rendering the list when loading flag is false.
Your render method should be like below
render()
{
if(this.props.isSpinnerLoading)
{
return (<View style={styles.loading}>
<ActivityIndicator size="large" color="#03A9F4"/>
</View> );
}
return (/** Actual List code here **/);
}
So what I do now: I am using Firebase for my React Native project.
The user writes another user's email in . Then there is a check if this email exists in database. If the email exists, then it writes as an array to users=[] in state and should be rendered in FlatList.
Everything works fine except one thing: FlatList doesn't render anything though I have an array.
That's what I receive from console.log(users):
[{...}]
0:
email: "test#gmail.com"
id: "-LSVedv_anPyD3We-4_Q"
That's how my code looks like:
state = {
promptVisible: false,
loading: false,
users: []
};
findUserEmail = (email) => {
firebase.database()
.ref(`/users`)
.orderByChild("email")
.equalTo(email)
.once("value")
.then(snapshot => {
if (snapshot.val()) {
const value = snapshot.val()
this.setState({ users: Object.keys(value).map((id) => ({
id,
...value[id]
})), promptVisible: false})
} else {
Alert.alert("Email doesn't exist")
}
})
}
renderItem({item}) {
return (
<View style = {styles.contactContainer}>
<View style={styles.userRow}>
<View style={styles.userImage}>
<Avatar
width={60}
rounded
source={{
uri: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/60/Matterhorn_from_Domhütte_-_2.jpg/1200px-Matterhorn_from_Domhütte_-_2.jpg"
}}
/>
</View>
<View>
<View style={styles.emailBackground}>
<Text
style = {styles.contact} >
{item.email}
</Text>
</View>
<Text
style = {styles.message} >
Da inne lauft öpis...
</Text>
</View>
</View>
</View>
)
}
render() {
console.log(this.state.users);
if (this.state.loading) {
return (
<View style={{alignItems: 'center', justifyContent: 'center', flex: 1}}>
<ActivityIndicator size="large" color="dodgerblue" />
</View>
)
}
return (
<View style={styles.container}>
<Header
centerComponent={{ text: 'Nachrichten', style: { color: '#FF0000', fontSize: 20, fontWeight: 'bold' } }}
outerContainerStyles={{ backgroundColor: '#ffffff' }}
rightComponent={this.renderButton()}
/>
<View style = {styles.contentContainer}>
<FlatList
data={this.state.users}
renderItem={this.renderItem}
keyExtractor={item => item.email}
/>
</View>
<Prompt
title="Email eingeben"
placeholder="Email"
visible={this.state.promptVisible}
onCancel={() => this.setState({promptVisible: false})}
onSubmit={(email) => this.findUserEmail(email)} />
</View>
);
}
So the question is what do I do wrong? And how can I fix it?
So I found an error. That was too simple and dumb in the same way.
I just deleted this component in render and everything worked fine.
<View style = {styles.contentContainer}>
Try replacing this...
<FlatList
data={this.state.users}
renderItem={this.renderItem}
keyExtractor={item => item.email}
/>
With a static, object-filled array in the shape of what you expect this.state.users to look like. Here's an example...
<FlatList
data={[{id: "A", email: "testA#gmail.com"},{id: "B", email: "testB#gmail.com"}]}
renderItem={this.renderItem}
keyExtractor={item => item.email}
/>
This won't solve your problem, but it's what I was suggesting as a troubleshooting step.