How to use firebase in DrawerNavigator and sync retrieve data - firebase

Objective:
I want to retrieve the users name from firebase and then use in the Text component, but it returns before the data can be loaded from firebase, which causes the Text gets undefined.
The Drawer code:
export default Slidebar = (props) => {
var name;
firebase.database().ref('users/' + firebase.auth().currentUser.uid + '/profile').once("value")
.then( (snapshot) => {
name = (snapshot.val().name)
console.log('snapshot name:', name)
})
return(
<ScrollView style={{backgroundColor: "#121212"}}>
<ImageBackground source={{uri: 'https://www.redebrasilatual.com.br/wp-content/uploads/2019/05/maconha-projeto.jpg'}}
style={{ padding: 16, paddingTop: 48 }}
>
<Text style={styles.name}> { name, console.log('text name: ', name) } </Text>
<Text style={styles.email}>email#example.com</Text>
<TouchableOpacity style={{height: 40, width: 40}} onPress={() => console.log(name)} >
<View style={{flex: 1, backgroundColor: 'white'}} />
</TouchableOpacity>
</ImageBackground>
<View style={styles.container}>
<DrawerNavigatorItems {...props} />
</View>
</ScrollView>
)
}
The console output:
INFO
17:06
text name: undefined
INFO
17:06
snapshot name: Joao Pedro

Solved!
i already tried useState before, but i think i did something wrong, but now its working well!
const [name, setName] = useState("teste");
const [email, setEmail] = useState("email");
firebase.database().ref('users/' + firebase.auth().currentUser.uid + '/profile').once("value")
.then( (snapshot) => {
setName(snapshot.val().name)
setEmail(snapshot.val().email)
})

Related

Error: [auth/unknown] Cannot create PhoneAuthCredential without either verificationProof, sessionInfo, temporary proof, or enrollment ID

I am trying to make a Login page with Phone Authentication to use React-Native-Firebase sdk and I receive OTP through sms and when I confirm the received OTP ,I got a error that: [Error: [auth/unknown] Cannot create PhoneAuthCredential without either verificationProof, sessionInfo, temporary proof, or enrollment ID.]
I am using-
React:18.0.0
React-Native: 0.69.1
React-Native-Firebase:^15.1.1
My code is-
import React, {useState} from 'react';
import {
View,
Text,
StyleSheet,
Image,
TextInput,
TouchableOpacity,
Alert,
} from 'react-native';
import PhoneInput from 'react-native-phone-number-input';
import auth from '#react-native-firebase/auth';
const Login = () => {
const [PhoneNumber, setPhoneNumber] = useState('');
const [otpInput, setOtpInput] = useState('');
const [confirmData, setConfirmData] = useState('');
const sendOtp = async () => {
try {
const responce = await auth().signInWithPhoneNumber(PhoneNumber);
setConfirmData(responce);
console.log(responce);
Alert.alert('Otp is sent please varify it');
} catch (error) {
console.log(error);
}
}
const submitOtp = async () => {
try {
const responce = await confirmData.confirm(otpInput);
console.log(responce);
Alert.alert('Your Number is verified');
} catch (error) {
console.log(error);
}
}
return (
<View>
<View style={styles.con}>
<Text style={styles.container}>Login Screen</Text>
<Image source={require('../assets/logo.png')} style={styles.image} />
</View>
<View style={styles.inputContainer}>
<Text style={styles.labels}>Phone Number:</Text>
<PhoneInput
style={styles.inputStyle}
defaultValue={PhoneNumber}
defaultCode="DM"
layout="first"
keyboardType="number-pad"
onChangeFormattedText={text => setPhoneNumber(text)}
onChangeText={(value) => setPhoneNumber(value)}
/>
</View>
<View>
<TouchableOpacity
style={styles.buttonStyle}>
<Text style={styles.buttonText}>Verify</Text>
</TouchableOpacity>
</View>
<View style={styles.otpContainer}>
<TextInput
style={styles.otpStyle}
placeholder="Enter OTP"
autoCapitalize="none"
secureTextEntry={true}
onChangeText={(value) => setOtpInput(value)}/>
</View>
<View>
<TouchableOpacity style={styles.continueStyle}>
<Text
style={styles.buttonText}
onPress={() => submitOtp()}>
Continue
</Text>
</TouchableOpacity>
</View>
</View>
);
};
export default Login;

Having issues rendering arrays of URLs in FlatLists in React Native

I am using Firebase v9 and React Native. I have one function and flatlist that is in charge of pulling and rendering group member data, and another function and flatlist that is in charge of rendering group posts. There are several issues going on here, but I would appreciate guidance on any part. I've been looking into this for a week.
The problem that I'm having is that the second flatlist is not rendering any images. I know that the styling is right because I've tried it with test data and I know that the URLs are being grabbed because I have can print a report of them. I've tried changing the way (item) is destructured, changing the renderItem functions, changing the parameters, and many more strategies, but nothing has worked.
I think it may have to do with the way that I'm storing my URLs in state and the temporary arrays I'm using. I'm also having the problem that the data doesn't load for the first flatlist when I first go to the screen, although it prints the right URLs. When I jump out and then go back to screen, the first flatlist renders the group members data (although the images are out of order sometimes). The data just prints out as Array [].
const MyGroupScreen = ({route, navigation}) => {
const { groupName, groupID } = route.params;
const [memNameLogs, setMemNameLogs] = useState([]);
const [memIDLogs, setMemIDLogs] = useState([]);
const [memImagesLogs, setMemImagesLogs] = useState([]);
const [memberCount, setMemberCount] = useState(0);
const [postIDLogs, setPostIDLogs] = useState([]);
const [postImagesLogs, setPostImagesLogs] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const getGroupInfo = async () => {
let memberIDs = [];
let memberNames = [];
let memberImages = [];
let userGroupsRef = collection(db, "groups", groupID, "members");
onSnapshot(userGroupsRef, (querySnapshot) => {
querySnapshot.forEach((document) => {
memberIDs.push(document.id)
onSnapshot(doc(db, "users", document.id), (snapshot) => {
const one = snapshot.data();
const two = one.firstName;
const three = one.lastName;
const four = two + ' ' + three;
memberNames.push(four);
});
const pathReference = ref(storage, 'userProfileImage/' + document.id);
getDownloadURL(pathReference)
.then((url) => {
memberImages.push(url);
})
});
setMemberCount(memberIDs.length);
setMemIDLogs(memberIDs);
setMemNameLogs(memberNames);
setMemImagesLogs(memberImages);
})
};
const getGroupPosts = async () => {
let postIDs = [];
let postImages = [];
let userPostsRef = collection(db, "groups", groupID, "posts");
onSnapshot(userPostsRef, (querySnapshot) => {
querySnapshot.forEach((document) => {
postIDs.push(document.id)
const postPathReference = ref(storage, 'posts/' + document.id + '/' + document.id + 0);
getDownloadURL(postPathReference)
.then((url) => {
postImages.push(url);
})
})
setPostIDLogs(postIDs);
setPostImagesLogs(postImages);
})
}
const [isFetching, setIsFetching] = useState(false);
const fetchData = () => {
getGroupPosts();
setIsFetching(false);
};
const onRefresh = () => {
setIsFetching(true);
fetchData();
};
useEffect(() => {
getGroupInfo();
getGroupPosts();
setIsLoading(false);
}, [])
const renderMembers = ({ item, index }) => (
<TouchableOpacity style={styles.memberInfo} onPress={()=>navigation.navigate('otherprofile', {userID: memIDLogs[index]})}>
<View style={{paddingBottom: 12}}>
<Image source={{uri: item}} style={styles.memberPicture}/>
</View>
<Text style={styles.memberName}>{memNameLogs[index]}</Text>
</TouchableOpacity>
);
const renderContent = ({ item, index }) => (
<TouchableOpacity onPress={()=>navigation.navigate('viewcontent')}>
<Image source={{uri: item}} style={styles.image}/>
</TouchableOpacity>
);
return (
<View style={styles.container}>
<View style={{alignItems:'center', width: width}}>
<View style={styles.groupBar}>
<View style={{flexDirection: 'row', flex: 1, justifyContent:'space-between', alignItems:'center'}}>
<View style={{flexDirection: 'row'}}>
<Text style={styles.groupName}>{groupName}</Text>
<Text style={styles.groupSize}>({memberCount})</Text>
</View>
</View>
<TouchableOpacity>
<Entypo name="menu" size={32} color={'#CACADB'}/>
</TouchableOpacity>
</View>
</View>
<FlatList
data={memImagesLogs}
renderItem={(item, index) => renderMembers(item, index)}
keyExtractor={item => item.id}
horizontal
showsHorizontalScrollIndicator='false'
style={{flex: 1}}
contentContainerStyle={{paddingTop: 12, paddingLeft: 24, backgroundColor: Colors.light.base, width: width}}
/>
<View style={{backgroundColor: Colors.light.base, height: 76, width: '100%', flexDirection:'row', alignItems:'center'}}>
<View style={{marginVertical: 36, marginLeft: 36, width: '15%', borderRadius: 15, height: 4, backgroundColor: '#CACADB'}}/>
</View>
<FlatList
data={postImagesLogs}
renderItem={(item, index) => renderContent(item, index)}
keyExtractor={item => item.id}
showsHorizontalScrollIndicator='false'
contentContainerStyle={{ paddingTop: 0, alignItems: 'center', justifyContent: 'flex-start'}}
columnWrapperStyle={{backgroundColor:Colors.light.base, width: width, justifyContent:'center'}}
style={{width: width}}
numColumns={4}
onRefresh={onRefresh}
refreshing={isFetching}
//extraData={postImages}
ListFooterComponent={()=>
<View style={{backgroundColor: Colors.light.base, height: '100%', width: width}}/>}
/>
<TouchableOpacity style={styles.addGroupButton} onPress={()=> navigation.navigate('newgroup', {screen: 'invitegroup', params: {groupID: groupID}})}>
<FontAwesome5 name='user-plus' size={20} color={Colors.light.base}/>
</TouchableOpacity>
</View>
);
}
export default MyGroupScreen;
In your useEffect(), you are calling getGroupPosts() which is an async function without an await or a .then()/.catch(). This is resulting in a behavior that will work sometimes work and not work. My suggestion is to call all async functions in your useEffect() like this:
getGroupInfo().catch(e => console.log(e));
getGroupPosts().catch(e => console.log(e));

Firebase react native flatlist keyExtractor

Im displaying some firebase data in a flatlist and im having trouble with the keyExtractor, I keep having the error:
undefined is not an object (evaluating "item.id")
I have added an id field to all my data in firebase and made sure they were a string but it's still not recognizing it as an id.
function Squad() {
const [gk, setGk] = useState([]);
useEffect(() => {
db.collection('squad').orderBy('position').get().then(snapshot => {
const gkData = snapshot.map(doc => {
const playerObject = doc.data();
return { name: playerObject.name, number: playerObject.number, id: playerObject.id };
});
setGk(gkData);
console.log(setGk);
});
}, []);
const Item = ({ name, number }) => (
<View style={styles.item}>
<Text style={styles.itemText}>{number} - {name}</Text>
</View>
);
const renderItem = ({ item }) => (
<Item name={item.name} number={item.number} />
)
return(
<View>
<View style={globalStyles.bar}>
<Text style={globalStyles.barText}>goalkeeper</Text>
</View>
<FlatList
data={setGk}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</View>
)
}
The data you are passing into the Flatlist is the setter function! You want to pass in ‘gk’ not ‘setGk’

How to pull key from firebase realtime database and pass to edit screen?

I am pretty new to react native/firebase, and am trying to figure out how to grab the unique key from an entry in the database (they are randomly generated when using Push), so I can update the database entry on my edit screen. Any help or direction on how I could accomplish this is very much appreciated.
Here is my main feed screen where all items from the database are grabbed and displayed:
let ref = db.ref('dogs');
export default class Main extends React.Component {
_isMounted = false;
constructor() {
super();
this.state = {
currentUser: null,
errorMessage: null,
items: [],
key: '',
};
}
componentDidMount() {
this._isMounted = true;
const {currentUser} = firebaseAuth;
this.setState({currentUser});
ref.on('value', snapshot => {
if (this._isMounted) {
let data = snapshot.val();
let items = Object.values(data);
this.setState({items});
}
});
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
const {currentUser} = this.state;
return (
<View style={styles.container}>
<View>
<View style={styles.container}>
{this.state.items.length > 0 ? (
<ItemComponent
style={styles.listDog}
items={this.state.items}
navigation={this.props.navigation}
/>
) : (
<Text>No dogs</Text>
)}
</View>
<View style={styles.bottomContainer}>
<TouchableOpacity
style={styles.addBtn}
onPress={() => this.props.navigation.navigate('dogCreation')}>
<View>
<FontAwesomeIcon style={styles.penIcon} icon={faBone} />
</View>
</TouchableOpacity>
</View>
</View>
</View>
);
}
}
here is my item component:
export default class ItemComponent extends Component {
static propTypes = {
items: PropTypes.array.isRequired,
};
render() {
return (
<View style={styles.itemsList}>
{this.props.items.map((item, dog) => {
return (
<TouchableOpacity
key={dog}
onPress={() =>
this.props.navigation.navigate('Profile', {
name: item.name,
image_uri: item.image_uri,
parent: item.parent,
parentEmail: item.parentEmail,
parentTwo: item.parentTwo,
parentTwoEmail: item.parentTwoEmail,
})
}>
<View style={styles.dogCard}>
<Image source={{uri: item.image_uri}} style={styles.dogImage} />
<Text style={styles.itemtext}>{item.name} </Text>
<FontAwesomeIcon style={styles.chevron} icon={faChevronRight} />
</View>
</TouchableOpacity>
);
})}
</View>
);
}
}
here is my profile page:
export default class Profile extends React.Component {
render() {
const {navigation} = this.props;
const dogName = navigation.getParam('name', '');
const image_uri = navigation.getParam('image_uri', '');
const parent = navigation.getParam('parent', '');
const parentEmail = navigation.getParam('parentEmail', '');
const parentTwo = navigation.getParam('parentTwo', '');
const parentTwoEmail = navigation.getParam('parentTwoEmail', '');
return (
<View style={styles.container}>
<Image style={styles.dogImage} source={{uri: image_uri}} />
<View style={styles.contentBlock}>
<Text style={styles.header}>Name</Text>
<Text style={styles.textStyle}>{dogName}</Text>
</View>
<View style={styles.contentBlock}>
<Text style={styles.header}>Pet Parent 1 Info</Text>
<Text style={styles.subHeader}>Name</Text>
<Text style={styles.textStyle}>{parent}</Text>
<Text style={styles.subHeader}>Name</Text>
<Text style={styles.textStyle}>{parentEmail}</Text>
</View>
<View style={styles.contentBlock}>
<Text style={styles.header}>Pet Parent 2 Info</Text>
<Text style={styles.subHeader}>Name</Text>
<Text style={styles.textStyle}>{parentTwo}</Text>
<Text style={styles.subHeader}>Name</Text>
<Text style={styles.textStyle}>{parentTwoEmail}</Text>
</View>
<TouchableOpacity
style={styles.addBtn}
onPress={() =>
this.props.navigation.navigate('editProfile', {
name: dogName,
image_uri: image_uri,
parent: parent,
parentEmail: parentEmail,
parentTwo: parentTwo,
parentTwoEmail: parentTwoEmail,
})
}>
<Text>EDIT</Text>
</TouchableOpacity>
</View>
);
}
}
and here is my edit profile page update function:
let ref = db.ref('dogs');
let addItem = (
dog,
parent,
parentEmail,
parentTwo,
parentTwoEmail,
image_uri,
) => {
db.ref('/dogs/')
.update({
name: dog,
parent: parent,
parentEmail: parentEmail,
parentTwo: parentTwo,
parentTwoEmail: parentTwoEmail,
image_uri: image_uri,
});
};
just use on return snapshot return snapshot.key.
ref.on('value', snapshot => {
if (this._isMounted) {
let id = snapshot.key;
let data = snapshot.val();
let items = Object.values(data);
this.setState({items});
}
});
you can see more details here: https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#key
**some important points, if you are using the firebase library directly in react native, I advise you to use the version created specifically for React Native, which corrects several problems of timers within the OS.
you can see here: https://rnfirebase.io/
**other importante detail, your firebase return function is a listener, and using this._isMounted is anti patern. you can use subscriber to stop the listener.
so...
let subscriber;
...
componentDidMount() {
const {currentUser} = firebaseAuth;
this.setState({currentUser});
subscriber = ref.on('value', snapshot => {
let data = snapshot.val();
let items = Object.values(data);
this.setState({items});
});
}
componentWillUnmount() {
// Stop listening for updates when no longer required
this.subscriber();
}

React-Native Passing users email and password to submit button

import FirebaseAPI from '../MyModules/FirebaseAPI';
function submit() {
import FirebaseAPI from '../MyModules/FirebaseAPI';
export default function LinksScreen() {
const [email, onChangeText] = React.useState('Enter Email');
const [password, onChangeText2] = React.useState('Enter Password');
const submit = () => {
FirebaseAPI.createUser(email, password)
}
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()}>
<View>
<Text>Submit</Text>
</View>
//code from FirebaseAPI.js
import * as firebase from 'firebase'
export const createUser = (email, password) => {
firebase.auth().createUserWithEmailAndPassword(email, password)
.catch((error) => console.log('createUser error: ', error));
}
//etc
my error is
TypeError: undefined is not an object (evaluating '_FirebaseAPI.default.createUser')
I assume its a scoping issue but unsure on how to fix it. Still new at react. Any help would be awesome!
The email and password are not scope of the submit function. You either need to move the submit function inside the component function or pass the values to the function
export default function LinksScreen() {
const [email, onChangeText] = React.useState('Enter Email');
const [password, onChangeText2] = React.useState('Enter Password');
const submit = () => {
FirebaseAPI.createUser(email, password)
}
return (
....
)
OR
<TouchableOpacity
style={{marginTop: '5%'}}
onPress= {() => submit(email, password)}>
<View>
<Text>Submit</Text>
</View>
</TouchableOpacity>
Also where you are importing the FirebaseAPI import as
import * as FirebaseAPI from '../MyModules/FirebaseAPI';

Resources