React-Native - Firebase data in TextInput - firebase

I could retrieve data from Firebase and display it immediately after. But when I try to use it in render, it is blank. I am new to react-native and might be doing something incorrect. How can I use data from Firebase in render ?
Here is my code:
componentWillMount() {
firebase.database().ref('/users/' + userId).once('value').then(function(snapshot) {
var DisplayEmail = snapshot.val().Email; alert(DisplayEmail);
});
}
render() {
return (
{alert(this.props.DisplayEmail)}
<TextInput style={styles.input}
autoFocus = {true}
autoCorrect = {false}
autoCapitalize = "none"
placeholder={this.DisplayEmail}
keyboardType="email-address"
underlineColorAndroid='transparent'
editable={false}
/>
)
}

Whenever you want to have something display on render, you should put it on state. By changing the state, you would cause the page to re-render and be updated with the new state. So when you do your firebase call, add it to state.
componentWillMount() {
firebase.database().ref('/users/' + userId).on('value', snapshot => {
this.setState({ DisplayEmail: snapshot.val().Email });
});
}
Calling set state just merges your state changes with your current state. Now you should be able to call state from render and have it work.
render() {
return (
{alert(this.props.DisplayEmail)}
<TextInput style={styles.input}
autoFocus={true}
autoCorrect={false}
autoCapitalize="none"
placeholder={this.state.DisplayEmail}
keyboardType="email-address"
underlineColorAndroid='transparent'
editable={false}
/>
)
}

it must be work :)
componentWillMount() {
firebase.database().ref('/users/' + userId)
.on('value', snapshot => {
this.state = { DisplayEmail: snapshot.val().Email
});
}
render() {
return (
{alert(this.props.DisplayEmail)}
<TextInput style={styles.input}
autoFocus = {true}
autoCorrect = {false}
autoCapitalize = "none"
placeholder={this.state.DisplayEmail}
keyboardType="email-address"
underlineColorAndroid='transparent'
editable={false}
/>
)
}

Related

read data from firebase realtime database using react native

I want to read data from firebase realtime database.
I want to fix my "function readData()"
like,
If I use this funcion, I want to read my data, without enter "username".
for example, I created this,
username:hello,
email:hello#gmail.com
and If I press "read data" button, (without enter 'username')
I want to read recent data. (username and email both)
please help me!
this is my app.js
import { StatusBar } from 'expo-status-bar';
import { useState } from 'react';
import { Button, button, StyleSheet, Text, TextInput, View } from 'react-native';
import { ref, set, update, onValue, remove } from "firebase/database";
import { db } from './components/config';
export default function App() {
const [username, setName] = useState('');
const [email, setEmail] = useState('');
function createData() {
set(ref(db, 'users/' + username), {
username: username,
email: email
}).then(() => {
// Data saved successfully!
alert('data created!');
})
.catch((error) => {
// The write failed...
alert(error);
});
}
function update() {
set(ref(db, 'users/' + username), {
username: username,
email: email
}).then(() => {
// Data saved successfully!
alert('data updated!');
})
.catch((error) => {
// The write failed...
alert(error);
});
}
function readData() {
const starCountRef = ref(db, 'users/' + username);
onValue(starCountRef, (snapshot) => {
const data = snapshot.val();
setEmail(data.email);
});
}
return (
<View style={styles.container}>
<Text>firebase</Text>
<TextInput value={username} onChangeText={(username) => {setName(username)}} placeholder='Username' style={styles.TextBoxes}></TextInput>
<TextInput value={email} onChangeText={(email) => {setEmail(email)}} placeholder='Email' style={styles.TextBoxes}></TextInput>
<Button title='create data' onPress={createData}></Button>
<Button title='update data' onPress={update}></Button>
<Button title='read data' onPress={readData}></Button>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
TextBoxes: {
width:'90%',
fontSize:18,
padding:12,
backgroundColor:'grey',
marginVertical:10,
}
});
I understand you want to call last username by default if username is empty.
For this, you can define lastUserName state and call it if username is empty, for example;
const [lastUserName, setLastUserName] = useState('');
readData() ,
function readData() {
const starCountRef = ref(db, 'users/' + username !== '' ? username : lastUserName);
onValue(starCountRef, (snapshot) => {
const data = snapshot.val();
setEmail(data.email);
});
}
Then, view should be like that;
<View style={styles.container}>
<Text>firebase</Text>
<TextInput value={username}
onChangeText={(username) => {
setName(username)
setLastUserName(username) // add this line
}
}
placeholder='Username' style={styles.TextBoxes}></TextInput>
<TextInput value={email} onChangeText={(email) => {setEmail(email)}} placeholder='Email' style={styles.TextBoxes}></TextInput>
<Button title='create data' onPress={createData}></Button>
<Button title='update data' onPress={update}></Button>
<Button title='read data' onPress={readData}></Button>
</View>
Note : If you want to keep this state in global use Redux.
Note: Use localStorage if you want the application to run on the same state after closing and reopening. see: https://github.com/react-native-async-storage/async-storage

this.props.route.params returns value as undefined

I'm building a barcode reader app that scans that qr code and then takes data and is used as a key to fetch an object from firebase. In order the data to be used as a key I need to pass through another screen but when I check console log it's cameback that the scanned key is undefined.
The itself barcode scanner works perfectly.
Barcode class :
export class BarCodeScannerScreen extends Component{
state = {
CameraPermissionGranted: null,
}
async componentDidMount() {
// Ask for camera permission
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ CameraPermissionGranted: status === "granted" ? true : false });
};
barCodeScanned = ({ data }) => {
//Access the Data
alert(data); // shows the scanned key
this.props.navigation.navigate('Info', {
item: data, }); // but then it's dissapears in here.
};
render(){
const { CameraPermissionGranted } = this.state;
if(CameraPermissionGranted === null){
// Request Permission
return(
<View style={styles.container}>
<Text>Please grant Camera permission</Text>
</View>
);
}
if(CameraPermissionGranted === false){
// Permission denied
return (
<View style={styles.container}>
<Text>Camera Permission Denied.</Text>
</View>
);
}
if(CameraPermissionGranted === true){
// Got the permission, time to scan
return (
<View style = {{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}>
<BarCodeScanner
onBarCodeScanned = {this.barCodeScanned }
style = {{
height: DEVICE_HEIGHT/1.1,
width: DEVICE_WIDTH,
}}
>
</BarCodeScanner>
</View>
);
}
}
}
Here is my Info screen that receives the information :
export default class InfoScreen extends Component {
constructor(props){
super(props);
this.state={
productlist:[],
scannedkey: this.props.route.params.item
} }
async componentDidMount(){
firebase.database().ref(`product/${ this.state.scannedkey}`).on(
"value",
(snapshot) => {
var list = [];
snapshot.forEach((child) => {
list.push({
key: child.key,
title: child.val().title,
//details: child.val().details,
//price: child.val().price
});
});
this.setState({ productlist: list });
},
(error) => console.error(error)
);
}
componentWillUnmount() {
if (this.valuelistener_) {
this.valueRef_.off("value", this.valuelistener_)
}}
render() {
console.log(this.state.scannedkey); // console log shows that scanned key is undefined
return(
<View style={styles.container}>
<Text>Hey</Text>
<Text>{this.state.productlist.title}</Text>
</View>
);}}
App.js
export default function App() {
const Drawer=createDrawerNavigator();
return (
<Provider store={store}>
<NavigationContainer>
<Drawer.Navigator initialRouteName="Barcode">
<Drawer.Screen name="Barcode" component={BarCodeScannerScreen} />
<Drawer.Screen name="Info" component={InfoScreen} />
</Drawer.Navigator>
</NavigationContainer>
</Provider>
);
}
I ussualy use function components to navigate through but with class components it's a little tricky for me. Perhaps I missed something?
So far I 've tried :
this.props.navigation.navigate('Info', {
item: JSON.stringify(data) , });
And it didn't work.
I will be grateful for your help.
Try to use item directly from props, not from state
in your componentDidMount call where you supply from state the scannedKey, supply it from props
firebase.database().ref(`product/${this.props.route.params.item}`)....
you are also calling this.props instead of props directly in your state inside your constructor, which have direct access to it, that's why you can call super(props) and not super(this.props), I am not sure if this is the issue, but in react docs says don't copy props to state because they get ignored, and it's bad practice my friend.
check this link, in the big yellow note what I am reffering to
https://reactjs.org/docs/react-component.html#constructor

mapping firebase read to props react-native

this might not be an issue with the mapping itself but i've read some data from my firebase realtime database into my sate and i'm trying to pass it as props then map it in a subsequent component.
I am getting the following error, I am using an android emulator:
TypeError: undefined is not a function (near ...'this.props.notes.map'...)
app.js (where I update the state)
state = {
loggedin: false,
notes: [
{
id: 1,
text: "mow the lawn",
author: "dean",
time: "10am"
},
{
id: 2,
text: "feed the dog",
author: "sam",
time: "2pm"
}
]
}
//passing props to notes component
<Notes style={styles.notes} notes={this.state.notes} />
updateNotes = async () => {
console.log("grabbing new notes");
const snapshot = await firebase.database().ref('Users/Notes').once('value');
console.log(snapshot.val())
this.setState({ notes: snapshot.val() });
};
my Notes component where I map the props
renderCondition =()=>{
if(this.state.Deleted === false){
return(
<View>
{this.props.notes.map(note => (
<View
style={styles.note}
key={note.author}
id={note.id}
>
<Text style={styles.noteHeader}>{note.author}</Text>
<Text style={styles.noteText}>{note.text}</Text>
<Text style={styles.noteTime}>{note.time}</Text>
<Button title= 'X' onPress={() => this.setState({Deleted:true}) }></Button>
</View>
))}
</View>
)
}
return(
<View>
<Text>are you sure you want to delete this note?</Text>
<Button title="Yes"></Button>
<Button onPress ={()=>{this.setState({Deleted:false})}} title="No"></Button>
</View>
)
}
render() {
return (
<View>
{this.renderCondition()}
</View>
);
}
You have to check whether the notes have been passed down or whether they are undefined or null. JavaScript is not going to map an undefined object.
Try the following code:
{this.props.notes && this.props.notes.map(note => (
// do stuff with each note...
))}
This will run the .map function only if the notes are neither undefined nor null.
So my issue was that I needed to update my notes state by making sure it was an array. I had mistakenly simply updated it as an object and then attempted to map the object. Here is my solution.
from this
updateNotes = async () => {
console.log("grabbing new notes");
const snapshot = await firebase.database().ref('Users/Notes').once('value');
console.log(snapshot.val())
this.setState({ notes: snapshot.val() });
};
to this
updateNotes = async () => {
console.log("grabbing new notes");
const snapshot = await firebase.database().ref('Users/Notes').once('value');
console.log(snapshot.val())
this.setState({ notes: [snapshot.val()] });
};

react native firebase authentication

In react native with firebase I get a chat app code. It used a button to show my registered friends, but I want to check when this button click user is logged in or not.
This is the button code in render function
render() {
return (
<View style={styles.containerl}>
<StatusBar barStyle="light-content" backgroundColor="red" />
<TouchableOpacity>
<Text
style={styles.buttonStyle}
onPress={() => this.props.navigation.navigate("Friendlist")}
>
SHOW FRIEND LIST
</Text>
</TouchableOpacity>
</View>
);
}
I want to add this firebase authentication code in to Show Friend List text press.
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('user logged')
}
});
Can anyone help me?
You can do like below. Add a flag to check whether the user logged in or not
state = {
isUserLogged: false
}
constructor(props) {
super(props);
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({
isUserLogged: true
})
} else {
this.setState({
isUserLogged: false
})
}
});
}
render() {
return (
<View style={styles.containerl}>
<StatusBar barStyle="light-content" backgroundColor="red" />
<TouchableOpacity>
<Text
style={styles.buttonStyle}
onPress={() => {
if (this.state.isUserLogged) {
this.props.navigation.navigate("Friendlist")
} else {
console.log('user not logged')
}
}
}
>
SHOW FRIEND LIST
</Text>
</TouchableOpacity>
</View>
);
}
In order to show whether a user is logged in or not, you'll need to attach a variable to the user state. So, your authentication code:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('user logged')
}
});
essentially, will put this method in either the constructor() or the componentDidMount() method.
From there, you'll need to set the state, like -
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({ userLoggedIn: true });
console.log('user logged')
}
});
and in your render() you can attach conditions to this.state.userLoggedIn on your onPress() method accordingly.
If you need to send the logged in state to your <Friendlist/> component, you'll be required to do -
this.props.navigation.navigate("Friendlist", {userLoggedIn: this.state.userLoggedIn})
and in your <Friendlist/> component you can fetch it from this.props.navigation.state.params.userLoggedIn

Populate ReactNative ListView with Firebase data

I've been struggling for a few days to get this working. I want to populate a ListView in React Native with data from my Firebase database. I have this setup:
const ListItem = require('./profileRow');
var database = firebase.database();
var userId, dataKey;
class Selection extends Component {
constructor(props) {
super(props);
userId = firebase.auth().currentUser.uid;
this.dataRef = firebase.database().ref('/users/' + userId + '/profiles_info');
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
})
};
}
listenForProfiles(dataRef){
dataRef.on('value', (snap) => {
var profiles = [];
snap.forEach((child) => {
profiles.push({
name: child.val().forename,
_key: child.key
});
});
alert(profiles);
this.setState({
dataSource: this.state.dataSource.cloneWithRows(profiles)
});
});
}
componentDidMount() {
this.listenForProfiles(this.dataRef);
}
render() {
return (
<Image source={require('../assets/bg.png')} style={styles.container}>
<View style={{flex: 1, flexDirection:'column'}}>
<Text>
Select a profile to view:
</Text>
</View>
<View style={{flex: 1}}>
<ListView dataSource={this.state.dataSource} renderRow={this._renderItem.bind(this)} enableEmptySections={true} style={styles.listview}> </ListView>
</View>
</Image>
);
}
_renderItem(item) {
return (
<ListItem item={item}/>
);
}
}
The datastructure looks like this:
So what I'm trying to do here is populate each row of the ListView with the "forename" String of each "profile" directory (0,1,2).
But on my alert() I am returned: [object Object],[object Object],[object Object] which must mean it is only fetching the directories as Objects from "profiles_info" and not each "forename" String from those directories.
This is where I am stuck, I hope someone can shed some light on this. I know what the solution should be, I just don't know how to apply it in code.
Thanks in advance!
You are pushing objects into your profiles array here, so it makes sense that your alerts are showing objects:
profiles.push({
name: child.val().forename,
_key: child.key
});
If you use alert(JSON.stringify(profiles)); instead of alert(profiles); you should see an array of objects with fields name and key. Accessing profiles[0].name would give the actual name.
Side note, if you use console.log instead of alert you get some more meaningful information.
Try Following Tutorial. may be help you.
react-native-firebase-tutorial-list

Resources