React native function auto submitting to firebase? - javascript

function submit(email, password) {
FirebaseAPI.createUser(email, password)
}
export default function LoginScreen() {
const [email, onChangeText] = React.useState('Enter Email');
const [password, onChangeText2] = React.useState('Enter Password');
const componentDidMount = () => {
this.watchAuthState(this.props.navigation)
}
const watchAuthState =(navigation) => {
firebase.auth().onAuthStateChanged(function(user) {
console.log('onauthStateChanged', user)
if (user) {
this.props.navigation.navigate('Main');
// this.props.navigation.navigate('App');
}
});
}
return (
<KeyboardAvoidingView style={styles.wrapper} behavior="padding">
<View style={styles.scrollViewWrapper}>
<ScrollView style={styles.scrollView}>
<Text style={styles.loginHeader}>Creat an Account </Text>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={text => onChangeText(text)}
value={email}
/>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={text => onChangeText2(text)}
value={password}
/>
<TouchableOpacity
style={{marginTop: '5%'}}
onPress= {(submit(email,password))}>
<View>
<Text>Submit</Text>
</View>
</TouchableOpacity>
</ScrollView>
</View>
</KeyboardAvoidingView>
);
}
Firebase is working fine with this function but I have an issue where even if I type say john#gmail.com password sfjkskfs etc it will auto send it to firebase even before I hit the submit button.
Any help would be awesome!

I think you are using the onPress function badly. you should use just like this one :
onPress = {() => this.submit(email,password)}

Related

How do I get the document ID of a specific document in Firebase on React Native?

I'm working on a project that allows users to write anonymous letters addressed to people by name and I want to add a like/dislike functionality to the app. I was confused on how to get the specific document ID for that post and also incrementing the likeCount by 1 (in the areas where the "????" are at in the code below) ? I want it to update the field "likeCount" in firebase by 1 when the thumbs up icon is pressed.
This is the portion of my code that contains the posts (data from firebase) that is mapped for each firebase document:
function Home() {
const [posts, setPosts] = useState([]);
const [searchValue, setSearchValue] = useState("");
const [filteredPosts, setFilteredPosts] = useState([]);
const collectionRef = collection(db, "posts");
useEffect(() => {
const getPosts = async () => {
const data = await getDocs(collectionRef);
const filteredRef = query(
collectionRef,
where(`recipiant`, "==", `${searchValue}`)
);
const querySnapshot = await getDocs(filteredRef);
let posts = [];
querySnapshot.forEach((doc) => {
posts.push(doc.data());
});
setFilteredPosts(posts);
setPosts(
searchValue
? filteredPosts
: data.docs.map((doc) => ({ ...doc.data() }))
);
};
getPosts();
}, [searchValue, filteredPosts]);
return (
<ImageBackground source={image} style={styles.image}>
<SafeAreaView style={styles.container}>
<ScrollView>
<View style={styles.header}>
<Text style={styles.title}>Home</Text>
</View>
<Pressable>
<Input
placeholder="Search for a name"
inputContainerStyle={styles.searchbar}
inputStyle={styles.searchInput}
placeholderTextColor="gray"
onChangeText={(text) => setSearchValue(text)}
/>
</Pressable>
{posts.map((post, key) => {
return (
<View style={styles.postWrapper} key={key}>
<View style={styles.btnWrapper}>
<View style={styles.likeBtn}>
<Icon
name="thumbs-up"
size={25}
color="#fff"
onPress={() => {
const postRef = doc(db, "posts", `????`);
updateDoc(postRef, {
likeCount: ????,
});
}}
/>
<Text style={styles.likeCount}>{post.likeCount}</Text>
</View>
<Icon
name="thumbs-down"
size={25}
color="#fff"
onPress={() => {}}
/>
</View>
<Card
containerStyle={{
backgroundColor: "rgba( 255, 255, 255, 0.5 )",
borderRadius: 50,
height: 300,
marginBottom: 25,
width: 330,
backdropFilter: "blur( 20px )",
padding: 20,
}}
>
<Card.Title style={styles.notepadHeader}>Message.</Card.Title>
<View style={styles.center}>
<ScrollView>
<Text style={styles.notepadText}>
To: <Text style={styles.name}>{post.recipiant}</Text>
</Text>
<Text style={styles.notepadTextLetter}>
{post.letter}
</Text>
<Text style={styles.notepadFooter}>
From:{" "}
<Text
style={{
color: "#9e4aba",
fontSize: 20,
}}
>
{post.displayName}
</Text>
</Text>
</ScrollView>
</View>
</Card>
</View>
);
})}
</ScrollView>
</SafeAreaView>
</ImageBackground>
);
}
This is how my Firestore looks like and I want to retrieve the document id in the circle.
First, you can add the document ID in 'posts' array as shown below:
const posts = querySnapshot.docs.map((d) => ({ id: d.id, ...d.data() }));
setFilteredPosts(posts);
Then you can read post ID when required:
<Icon
name = "thumbs-up"
size = {25}
color = "#fff"
onPress = {() => {
const postRef = doc(db, "posts", post.id);
updateDoc(postRef, {
likeCount: ?? ?? ,
});
}
}
/>
This will give you the particular doc and perform updateDoc query accordingly.
query(collections('collection_name), where(documentId(), '==', 'your_post_id'))

How to save route.params with asyncstorage?

Srry if the title makes no sense. Don't know a better title.
How can I save route.params items that I pass to my second screen using AsyncStorage?
In my first screen i have a bunch of data in a FlatList that can be opened with a Modal. Inside that Modal I have a TouchableOpacity that can send the data thats inside the Modal to my second screen. The data that has been passed to the second screen is passed to a FlatList. The data in the FlatList should be saved to AsyncStorage. Tried alot of things getting this to work, but only getting warning message
undefined. Code below is the most recent progress.
Using React Navigation V5.
FIRST SCREEN
const [masterDataSource, setMasterDataSource] = useState(DataBase);
const [details, setDetails] = useState('');
<TouchableOpacity
onPress={() => {
const updated = [...masterDataSource];
updated.find(
(item) => item.id === details.id,
).selected = true;
setMasterDataSource(updated);
navigation.navigate('cart', {
screen: 'cart',
params: {
items: updated.filter((item) => item.selected),
},
});
setModalVisible(false);
}}>
<Text>Add to cart</Text>
</TouchableOpacity>
SECOND SCREEN
import React, { useEffect, useState } from 'react';
import { View, Text, FlatList, TouchableOpacity } from 'react-native';
import { useTheme } from '../Data/ThemeContext';
import AsyncStorage from '#react-native-async-storage/async-storage';
import Ionicons from 'react-native-vector-icons/Ionicons';
export default function ShoppingList({ route, navigation }) {
const [shoppingList, setShoppingList] = useState([]);
const { colors } = useTheme();
const todo = () => {
alert('Todo');
};
useEffect(() => {
restoreShoppingListAsync();
}, []);
const shoppingListAsync = () => {
const shoppingList = route.params && route.params.items;
setShoppingList(list);
storeShoppingList(list);
};
const asyncStorageKey = '#ShoppingList';
const storeShoppingListAsync = (list) => {
const stringifiedList = JSON.stringify(list);
AsyncStorage.setItem(asyncStorageKey, stringifiedList).catch((err) => {
console.warn(err);
});
};
const restoreShoppingListAsync = () => {
AsyncStorage.getItem(asyncStorageKey)
.then((stringifiedList) => {
console.log(stringifiedList);
const parsedShoppingList = JSON.parse(stringifiedList);
if (!parsedShoppingList || typeof parsedShoppingList !== 'object')
return;
setShoppingList(parsedShoppingList);
})
.then((err) => {
console.warn(err);
});
};
const RenderItem = ({ item }) => {
return (
<View>
<TouchableOpacity
style={{
marginLeft: 20,
marginRight: 20,
elevation: 3,
backgroundColor: colors.card,
borderRadius: 10,
}}>
<View style={{ margin: 10 }}>
<Text style={{ color: colors.text, fontWeight: '700' }}>
{item.name}
</Text>
<Text style={{ color: colors.text }}>{item.gluten}</Text>
<Text style={{ color: colors.text }}>{item.id}</Text>
</View>
</TouchableOpacity>
</View>
);
};
const emptyComponent = () => {
return (
<View style={{ alignItems: 'center' }}>
<Text style={{ color: colors.text }}>Listan är tom</Text>
</View>
);
};
const itemSeparatorComponent = () => {
return (
<View
style={{
margin: 3,
}}></View>
);
};
return (
<View
style={{
flex: 1,
}}>
<View
style={{
padding: 30,
backgroundColor: colors.Textinput,
elevation: 12,
}}>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<Ionicons name="arrow-back-outline" size={25} color="#fff" />
</TouchableOpacity>
<Text style={{ color: '#fff', fontSize: 20 }}>Inköpslista</Text>
<TouchableOpacity>
<Ionicons
name="trash-outline"
size={25}
color="#fff"
onPress={() => todo()}
/>
</TouchableOpacity>
</View>
</View>
<View style={{ flex: 1, marginTop: 30 }}>
<FlatList
data={shoppingList}
renderItem={RenderItem}
ListEmptyComponent={emptyComponent}
ItemSeparatorComponent={itemSeparatorComponent}
initialNumToRender={4}
maxToRenderPerBatch={5}
windowSize={10}
removeClippedSubviews={true}
updateCellsBatchingPeriod={100}
showsVerticalScrollIndicator={true}
contentContainerStyle={{ paddingBottom: 20 }}
/>
</View>
</View>
);
}
As you are using async storage to maintain the cart.
I would suggest an approach as below
Update the asyn storage when new items are added to or removed from the cart
Retrieve the items from the cart screen and show the items there
Before you navigate store the items like below
AsyncStorage.setItem(
'Items',
JSON.stringify(updated.filter((item) => item.selected))
).then(() => {
navigation.navigate('Cart', {
items: updated.filter((item) => item.selected),
});
});
The cart screen would be something like below
function Cart({ navigation, route }) {
const [data,setData]=useState([]);
React.useEffect(() => {
async function fetchMyAPI() {
const value = await AsyncStorage.getItem('Items');
setData(JSON.parse(value));
}
fetchMyAPI();
}, []);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button title="Go back" onPress={() => navigation.goBack()} />
<FlatList
data={data}
renderItem={RenderItem}
/>
</View>
);
}
Working Example
https://snack.expo.io/#guruparan/cartexample

too many re-renders when data moved to a separate component

Currently, I am using this logic to render data on the basis of results from a grapqhl query. This works fine:
const contacts = () => {
const { loading, error, data } = useUsersQuery({
variables: {
where: { id: 1 },
},
});
if (data) {
console.log('DATA COMING', data);
const contactName = data.users.nodes[0].userRelations[0].relatedUser.firstName
.concat(' ')
.concat(data.users.nodes[0].userRelations[0].relatedUser.lastName);
return (
<View style={styles.users}>
<View style={styles.item} key={data.users.nodes[0].id}>
<Thumbnail
style={styles.thumbnail}
source={{
uri:
'https://cdn4.iconfinder.com/data/icons/avatars-xmas-giveaway/128/girl_avatar_child_kid-512.png',
}}></Thumbnail>
<Text style={styles.userName}>{contactName}</Text>
</View>
</View>
);
}
};
return (
<SafeAreaView style={{ flex: 1 }}>
<Container style={{ flex: 1, alignItems: 'center' }}>
<Item style={styles.addToWhitelist}>
<Icon name="add" onPress={() => navigation.navigate('AddContact')} />
<Text style={styles.addToContactTitle}>Add contact</Text>
</Item>
<Text onPress={() => navigation.navigate('Home')}>Zurück</Text>
<View style={{ width: moderateScale(350) }}>
<Text>Keine Kontacte</Text>
</View>
{contacts()}
{/* <ContactList data={userData}></ContactList> */}
</Container>
</SafeAreaView>
);
};
However, when I make a separate component :
export const ContactList: React.FunctionComponent<UserProps> = ({
data,
}) => {
console.log('user called');
if (!data) return null;
console.log('DATA COMING', data);
const contactName = data.users.nodes[0].userRelations[0].relatedUser.firstName
.concat(' ')
.concat(data.users.nodes[0].userRelations[0].relatedUser.lastName);
return (
<View style={styles.users}>
<View style={styles.item} key={data.users.nodes[0].id}>
<Thumbnail
style={styles.thumbnail}
source={{
uri:
'https://cdn4.iconfinder.com/data/icons/avatars-xmas-giveaway/128/girl_avatar_child_kid-512.png',
}}></Thumbnail>
<Text style={styles.userName}>{contactName}</Text>
</View>
</View>
);
};
and call it like this:
const [userData, setUserData] = useState<UsersQueryHookResult>('');
const contacts = () => {
console.log('running');
const { loading, error, data } = useUsersQuery({
variables: {
where: { id: 1 },
},
});
if (data) {
setUserData(data);
}
};
return (
<SafeAreaView style={{ flex: 1 }}>
<Container style={{ flex: 1, alignItems: 'center' }}>
<Item style={styles.addToWhitelist}>
<Icon name="add" onPress={() => navigation.navigate('AddContact')} />
<Text style={styles.addToContactTitle}>Add contact</Text>
</Item>
<Text onPress={() => navigation.navigate('Home')}>Zurück</Text>
<View style={{ width: moderateScale(350) }}>
<Text>Keine Kontacte</Text>
</View>
{/* {contacts()} */}
<ContactList data={userData}></ContactList>
</Container>
</SafeAreaView>
);
};
However, this gives me a too many re-renders issue. What am I missing? Probably something basic. I also tried using useEffects but I can't run a graphql query hook inside it. That gives me an invalid hook call error.
It seems your running in an endless recursion.
If you call contacts in you render block it causes a setState (through setUserData) which renders, so contacts is called once again and so on till infinite (or till the error).

Updating informations from modal-React native

On my react native app I display information that I fetched from the server this way:
So when I click update profil, I display a modal with text input on it in order to give the user the opportunity to change the information of his profile. The modal look like this:
Now I already created a Fetch Post function that, when I click on the button update it sends static information to the server and the modal closes. but the profile page doesn't refresh until I get out of it and come back.
My question is: whats the best way to get the values from the textinputs, send them through post. and refresh the screen after the modal closes?. Should i use formik?
Here is a look at my code:
export default function MprofilScreen({ navigation }) {
const [modalVisible, setModalVisible] = useState(false);
const [Data, setData] = useState([]);
useEffect(() => {
fetch('******')
.then((response) => response.json())
.then((res) => {
console.log("repooooonse")
console.log(res)
setData(res)
})
.done();
}, []);
return (
<View style={{ flex: 1, backgroundColor: 'white' }} >
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
}}>
<View style={styles.modalView}>
<TouchableOpacity
style={{ ...styles.openButton, backgroundColor: "#2196F3" }}
onPress={() => {
setModalVisible(!modalVisible);
}}
>
<Text style={styles.textStyle}>close</Text>
</TouchableOpacity>
<ScrollView>
<Text style={styles.text}>Nom:</Text>
<TextInput style={styles.text_input} placeholder="nom" />
....
<Text style={styles.text}>Ville :</Text>
<TextInput style={styles.text_input} placeholder="Ville " />
<TouchableOpacity
style={{ ...styles.openButton, backgroundColor: "#2196F3" }}
onPress={() => {
setModalVisible(!modalVisible);
}}
>
<Text style={styles.textStyle}>Delete</Text>
</TouchableOpacity>
</ScrollView>
</View>
</Modal>
<TouchableOpacity style={styles.btn}
onPress={() => {
setModalVisible(true);
}}>
<Text style={{ color: 'white', fontSize: 15 }}> Update profil</Text>
</TouchableOpacity>
<View >
<View style={styles.main_container}>
<Text style={styles.text}>Nom:</Text>
<Text style={styles.text1}>{Data.nom}</Text>
</View>
.....
<View style={styles.main_container}>
<Text style={styles.text}>Ville:</Text>
<Text style={styles.text1}> {Data.ville}</Text>
</View>
</View>
</View>
);
}
I'm new to react native and I'll appreciate your help!
I'll assume you have the fetching details in componentDidMount of that profile page, and since modal also resides in it, so page doesnt refresh. What you can do is call that function again on modalClose.
suppose you have,
getDetails = () => {
.... fetch details
}
and in componentDidMount you call like :
componentDidmount(){
this.getDetails();
}
So same you can call on modalClose the same function after updating it.
onModalClose = () => {
this.getDetails()
}
hope its clear.feel free for doubtys

Undefined TextInput Value

I want to submit value from text input, but when I console.log, the text that inputed before is undefined. I've already follow the instruction from react native get TextInput value, but still undefined.
this is state that I've made before:
this.state = {
comment_value: '',
comments: props.comments
}
submit = (args) => {
this.props.submit(args.comment_value)
}
this is the the function for submitted text:
addComment () {
var comment_value = this.state.comment_value
console.log('success!', comment_value)
})
this.props.submit('410c8d94985511e7b308b870f44877c8', '', 'e18e4e557de511e7b664b870f44877c8')
}
and this is my textinput code:
<TextInput
underlineColorAndroid='transparent'
placeholder='Enter your comment here'
multiline numberOfLines={4}
onChangeText={(text) => this.setState({comment_value: text})}
value={this.state.comment_value}
style={styles.textinput}
/>
</View>
<TouchableOpacity onPress={this.addComment.bind(this)}>
<View style={{flex: 1, flexDirection: 'column', backgroundColor: Colors.background, width: 70}}>
<Icon name='direction' type='entypo' color='#000'size={30} style={styles.icon} />
</View>
</TouchableOpacity>
This should definately be working try cleaning up your code like this
contructor(props) {
super(props);
this.state = {
comment_value: '',
}
}
addComment () {
console.log(this.state.comment_value); // should be defined
this.props.submit(this.state.comment_value);
}
render() {
return (
<View>
<TextInput
underlineColorAndroid='transparent'
placeholder='Enter your comment here'
multiline numberOfLines={4}
value={this.state.comment_value}
onChangeText={(text) => this.setState({comment_value: text})}
style={styles.textinput}
/>
<TouchableOpacity onPress={this.addComment.bind(this)}>
<View style={{flex: 1, flexDirection: 'column', backgroundColor: Colors.background, width: 70}}>
<Icon name='direction' type='entypo' color='#000'size={30} style={styles.icon} />
</View>
</TouchableOpacity>
</View>
);
}
EDIT: Based on your complete code sample it seems like you're incorrectly trying to update state by doing multiple this.state = ... which is incorrect, to update state you have to use this.setState({ ... })

Categories

Resources