Firebase on listener with react native - javascript

So I'm trying to attach a .on listener, like so
firebase.database().ref('Users').child('AhvRcIT2anTaucSDoOgt2MLNxgZ2').on('value', snap => {
const user = snap.val();
alert(true);
}).catch(e => alert(e))
The problem is, I get an error saying
Setting a timer for a long period of time, i.e. multiple minutes, is a performance and correctness issue on Android as it keeps the timer module awake, and timers can only be called when the app is in the foreground. See https://github.com/facebook/react-native/issues/12981 for more info. (Saw setTimeout with duration 398331ms)
which I guess makes sense. The only solutions I could find were to just hide the warning, which sounds like a bad idea. Especially that my app started freezing after a while when I added this listener.
I know there is react-native-firebase available, but I've read all it does, is just hide the warning, not really solving the problem.
How can this problem be solved though? Or does it just have to be like this on Android?
Entire home class
export default class HomeScreen extends React.Component {
static navigationOptions = {
header: null,
};
componentWillMount() {
(async () => {
await firebase.auth().signInAndRetrieveDataWithEmailAndPassword('loigin', 'pass');
const val = await firebase.database().ref('Users').child('AhvRcIT2anTaucSDoOgt2MLNxgZ2').once('value').then(r => r.val()).catch(e => alert(e));
alert(val);
})();
}
render() {
// firebase.database().ref('Users').child('AhvRcIT2anTaucSDoOgt2MLNxgZ2').on('value', snap => {
// const user = snap.val();
// alert(true);
// }).catch(e => alert(e))
alert(false)
return (
<View style={styles.container}>
<ScrollView style={styles.container} contentContainerStyle={styles.contentContainer}>
<View style={styles.welcomeContainer}>
<Image
source={
__DEV__
? require('../assets/images/robot-dev.png')
: require('../assets/images/robot-prod.png')
}
style={styles.welcomeImage}
/>
</View>
<View style={styles.getStartedContainer}>
{this._maybeRenderDevelopmentModeWarning()}
<Text style={styles.getStartedText}>Get started by opening</Text>
<View style={[styles.codeHighlightContainer, styles.homeScreenFilename]}>
<MonoText style={styles.codeHighlightText}>screens/HomeScreen.js</MonoText>
</View>
<Text style={styles.getStartedText}>
Change this text and your app will automatically reload.
</Text>
</View>
<View style={styles.helpContainer}>
<TouchableOpacity onPress={this._handleHelpPress} style={styles.helpLink}>
<Text style={styles.helpLinkText}>Help, it didn’t automatically reload!</Text>
</TouchableOpacity>
</View>
</ScrollView>
<View style={styles.tabBarInfoContainer}>
<Text style={styles.tabBarInfoText}>This is a tab bar. You can edit it in:</Text>
<View style={[styles.codeHighlightContainer, styles.navigationFilename]}>
<MonoText style={styles.codeHighlightText}>navigation/MainTabNavigator.js</MonoText>
</View>
</View>
</View>
);
}
_maybeRenderDevelopmentModeWarning() {
if (__DEV__) {
const learnMoreButton = (
<Text onPress={this._handleLearnMorePress} style={styles.helpLinkText}>
Learn more
</Text>
);
return (
<Text style={styles.developmentModeText}>
Development mode is enabled, your app will be slower but you can use useful development
tools. {learnMoreButton}
</Text>
);
} else {
return (
<Text style={styles.developmentModeText}>
You are not in development mode, your app will run at full speed.
</Text>
);
}
}
_handleLearnMorePress = () => {
WebBrowser.openBrowserAsync('https://docs.expo.io/versions/latest/guides/development-mode');
};
_handleHelpPress = () => {
WebBrowser.openBrowserAsync(
'https://docs.expo.io/versions/latest/guides/up-and-running.html#can-t-see-your-changes'
);
};
}

You can try below for your componentWillMount
componentWillMount() {
firebase
.auth()
.createUserWithEmailAndPassword('loigin', 'pass')
.then(() => {
firebase.database()
.ref('Users')
.child('AhvRcIT2anTaucSDoOgt2MLNxgZ2').on('value', function (snapshot) {
alert(snapshot.val())
})
.catch(e => alert(e));
})
.catch(error => {
alert(error.message)
})
}

Related

Possible Unhandled Promise Rejection (id: 0):

I need some tips about this error. I think the code might need a bunch of 'try' and 'catch' functions? I am new to this and I don't know how to properly implement them.
Question: should the audio recorder record audio even with this warning happening?( this code is meant to integrate an audio recorder: Audio recorder npm package link )
Btw I am running the latest version of react native, I also only wrote code inside App.js (besides giving android permisions and completing the post-installation process) since in the latest version of react the linking of packages becomes Auto-Link which means the linking happens on installing a package (Source: https://reactnative.dev/blog/2022/06/21/version-069 )
App.js :
import React, {Component} from 'react';
import AudioRecorderPlayer from 'react-native-audio-recorder-player';
import {
StyleSheet,
View,
TouchableOpacity,
} from 'react-native';
const App = () => {
const audioRecorderPlayer = new AudioRecorderPlayer();
const onStartRecord = async () => {
const result = await this.audioRecorderPlayer.startRecorder();
this.audioRecorderPlayer.addRecordBackListener((e) => {
this.setState({
recordSecs: e.currentPosition,
recordTime: this.audioRecorderPlayer.mmssss(
Math.floor(e.currentPosition),
),
});
return;
});
console.log(result);
};
const onStopRecord = async () => {
const result = await this.audioRecorderPlayer.stopRecorder();
this.audioRecorderPlayer.removeRecordBackListener();
this.setState({
recordSecs: 0,
});
console.log(result);
};
const onStartPlay = async () => {
console.log('onStartPlay');
const msg = await this.audioRecorderPlayer.startPlayer();
console.log(msg);
this.audioRecorderPlayer.addPlayBackListener((e) => {
this.setState({
currentPositionSec: e.currentPosition,
currentDurationSec: e.duration,
playTime: this.audioRecorderPlayer.mmssss(Math.floor(e.currentPosition)),
duration: this.audioRecorderPlayer.mmssss(Math.floor(e.duration)),
});
return;
});
};
const onPausePlay = async () => {
await this.audioRecorderPlayer.pausePlayer();
};
const onStopPlay = async () => {
console.log('onStopPlay');
this.audioRecorderPlayer.stopPlayer();
this.audioRecorderPlayer.removePlayBackListener();
};
return (
<View>
<View style={{backgroundColor:'black',alignSelf:'center',marginTop:'3%'}}>
<TouchableOpacity onPress={onStartRecord}>
<Text style={styles.twhite}>Start Record</Text>
</TouchableOpacity>
</View>
<View style={{backgroundColor:'black',alignSelf:'center',marginTop:'3%'}}>
<TouchableOpacity onPress={onStopRecord}>
<Text style={styles.twhite}>Stop Record</Text>
</TouchableOpacity>
</View>
<View style={{backgroundColor:'black',alignSelf:'center',marginTop:'3%'}}>
<TouchableOpacity onPress={onStartPlay}>
<Text style={styles.twhite}>Start Play</Text>
</TouchableOpacity>
</View>
<View style={{backgroundColor:'black',alignSelf:'center',marginTop:'3%'}}>
<TouchableOpacity onPress={onPausePlay}>
<Text style={styles.twhite}>Pause Play</Text>
</TouchableOpacity>
</View>
<View style={{backgroundColor:'black',alignSelf:'center',marginTop:'3%'}}>
<TouchableOpacity onPress={onStopPlay}>
<Text style={styles.twhite}>Stop Play</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
twhite: {
color:'white',
fontSize:18,
},
});
export default App;

Rendering Firebase data in map function

I'm trying to render data from a firebase get function but it isn't displaying anything. The images console.log displays 2 values but it doesn't get rendered on the page. Does anyone have suggestions why that is.
function cards(){
store.collection('users').get().then(snapshot => {
images = snapshot.docs.map(doc => doc.data().image)
console.log(images)
return images.map((doc) => {
return (
<Card style={[styles.card, styles.card1]}>
<Text style={styles.label}>A</Text>
</Card>
)
})
})
}
return (
<View>
<View style={styles.viewport}>
<CardStack style={styles.content}>
{cards()}
</CardStack>
</View>
</View>
)
}
You are trying to call a asynchrounous function and get a return from it by using a then. You will always get an undefined from it because the then finished when your function already returned undefined or in this case nothing.
Try it with using a state and handling the async call correctly like here:
import React, { useState, useEffect } from "react";
const YourComponent = () => {
const [list, setLits] = useState([]);
useEffect(() => {
const snapshot = await store.collection("users").get();
const images = [];
snapshot.docs.forEach((s) => {
images.push(doc.data().image);
});
setLits(images);
}, []);
return (
<View>
<View style={styles.viewport}>
<CardStack style={styles.content}>
{list.map((i) => {
return (
<Card style={[styles.card, styles.card1]}>
<Text style={styles.label}>A</Text>
</Card>
);
})}
</CardStack>
</View>
</View>
);
};

Delay style display when using Pressable React Native component

I'm using the Pressable React Native component for items displayed in a FlatList.
I want to be able to scroll back and forth through the list and have no feedback from the items, unless pressed for a a little while.
The onPress function invoked can easily be delayed with the onLongPress capability, however I also want to invoke an opacity over the item after it's been pressed for a little while, NOT during scrolling. There doesn't seem to be an easy way to do this. What I've tried so far without succes:
.........
const sleep = (milliseconds: any) => {
return new Promise(resolve => setTimeout(resolve, milliseconds));
};
const display = (pressed: boolean) => {
if (pressed) {
sleep(3000).then(() => {
return true;
});
}
return false;
};
const ItemInList: FunctionComponent<ItemInListProps> = ({
style,
colors,
title = '',
text,
subtext,
children,
onPress,
}) => {
return (
<Pressable
onLongPress={onPress}
delayLongPress={3000}
style={({ pressed }) => [
{
opacity: display(pressed) ? 0.2 : 1,
},
]}>
<LinearGradient
colors={colors || []}
style={StyleSheet.flatten([styles.container, style])}>
<View style={styles.titleContainer}>
<Text style={styles.titleStyle}>{title}</Text>
</View>
<View style={subtext ? styles.subtextContainer : styles.textContainer}>
<Text style={styles.textStyle}>{text}</Text>
</View>
{subtext && (
<View style={styles.subtextContainer}>
<Text style={styles.subtextStyle}>{subtext}</Text>
</View>
)}
{children}
</LinearGradient>
</Pressable>
);
};
export default ItemInList;
This has no effect whatsoever, opacity is never displayed.
Does anyone have a good idea about how to handle this?
Thanks.
Can you try TouchableOpacity? it has props delayPressIn and many props u can try these
I'm pretty sure that when the OP has asked this question, there was no straightforward solution.
Right now you can use the "unstable_pressDelay" provided prop to define a number of milliseconds to delay the pressable activation.
Example code:
<Pressable
unstable_pressDelay={5000}
onPress={() => {
setTimesPressed((current) => current + 1);
}}
style={({ pressed }) => [
{
backgroundColor: pressed
? 'rgb(210, 230, 255)'
: 'white'
},
styles.wrapperCustom
]}>
{({ pressed }) => (
<Text style={styles.text}>
{pressed ? 'Pressed!' : 'Press Me'}
</Text>
)}
</Pressable>
Documentation: https://reactnative.dev/docs/pressable#unstable_pressdelay

React Native Swipeable close after onPress not working

So I've seen many posting the same problem, but for some I don't seem to be able to adapt the posted solutions to my case.. I hope someone can tell me exactly what changes I need to do in order to get this working, since I don't know how to implement the suggested solutions!
I am using React Native Swipeable
Example of someone having the same issue
I have a file in which I built the Swipeable Component and an other class which calls the component. I've set a timeout close function on the onSwipeableOpen as a temporary solution. But ideally it should close immediately upon pressing "delete". The "..." stands for other code which I deleted since it's not important for this case.
AgendaCard.js
...
const RightActions = ({ onPress }) => {
return (
<View style={styles.rightAction}>
<TouchableWithoutFeedback onPress={onPress}>
<View style={{ flexDirection: "row", alignSelf: "flex-end" }}>
<Text style={styles.actionText}>Löschen</Text>
<View style={{ margin: 5 }} />
<MaterialIcons name="delete" size={30} color="white" />
</View>
</TouchableWithoutFeedback>
</View>
);
};
...
export class AgendaCardEntry extends React.Component {
updateRef = (ref) => {
this._swipeableRow = ref;
};
close = () => {
setTimeout(() => {
this._swipeableRow.close();
}, 2000);
};
render() {
return (
<Swipeable
ref={this.updateRef}
renderRightActions={() => (
<RightActions onPress={this.props.onRightPress} />
)}
onSwipeableOpen={this.close}
overshootRight={false}
>
<TouchableWithoutFeedback onPress={this.props.onPress}>
<View style={styles.entryContainer}>
<Text style={styles.entryTitle}>{this.props.item.info}</Text>
<Text style={styles.entryTime}>
eingetragen um {this.props.item.time} Uhr
</Text>
</View>
</TouchableWithoutFeedback>
</Swipeable>
);
}
}
Agenda.js
...
renderItem(item) {
...
<AgendaCardAppointment
item={item}
onRightPress={() => firebaseDeleteItem(item)}
/>
...
}
I'm having the same issue and have been for days. I was able to hack through it, but it left me with an animation I don't like, but this is what I did anyways.
export class AgendaCardEntry extends React.Component {
let swipeableRef = null; // NEW CODE
updateRef = (ref) => {
this._swipeableRow = ref;
};
close = () => {
setTimeout(() => {
this._swipeableRow.close();
}, 2000);
};
onRightPress = (ref, item) => { // NEW CODE
ref.close()
// Delete item logic
}
render() {
return (
<Swipeable
ref={(swipe) => swipeableRef = swipe} // NEW CODE
renderRightActions={() => (
<RightActions onPress={() => this.onRightPress(swipeableRef)} /> // NEW CODE
)}
onSwipeableOpen={this.close}
overshootRight={false}
>
<TouchableWithoutFeedback onPress={this.props.onPress}>
<View style={styles.entryContainer}>
<Text style={styles.entryTitle}>{this.props.item.info}</Text>
<Text style={styles.entryTime}>
eingetragen um {this.props.item.time} Uhr
</Text>
</View>
</TouchableWithoutFeedback>
</Swipeable>
);
}
}

Undefined is not an object evaluating this.state/this.props

How do I bind a function outside of scope in React Native? I'm getting the errors:
undefined is not an object evaluating this.state
&
undefined is not an object evaluating this.props
I'm using the render method to evoke renderGPSDataFromServer() when the data has been loaded. The problem is, I'm trying to use _buttonPress() and calcRow() inside of renderGPSDataFromServer(), but I'm getting those errors.
I've added
constructor(props) {
super(props);
this._buttonPress = this._buttonPress.bind(this);
this.calcRow = this.calcRow.bind(this);
to my constructor and I've changed _buttonPress() { to _buttonPress = () => { and still nothing.
I think I understand the problem but I don't know how to fix it:
renderLoadingView() {
return (
<View style={[styles.cardContainer, styles.loading]}>
<Text style={styles.restData}>
Loading ...
</Text>
</View>
)
}
_buttonPress = () => {
this.props.navigator.push({
id: 'Main'
})
}
renderGPSDataFromServer =() => {
const {loaded} = this.state;
const {state} = this.state;
return this.state.dataArr.map(function(data, i){
return(
<View style={[styles.cardContainer, styles.modularBorder, styles.basePadding]} key={i}>
<View style={styles.cardContentLeft}>
<TouchableHighlight style={styles.button}
onPress={this._buttonPress().bind(this)}>
<Text style={styles.restData}>View Video</Text>
</TouchableHighlight>
</View>
<View style={styles.cardContentRight}>
<Text style={styles.restData}>{i}</Text>
<View style={styles.gpsDataContainer}>
<Text style={styles.gpsData}>
{Number(data.lat).toFixed(2)}</Text>
<Text style={styles.gpsData}>{Number(data.long).toFixed(2)}</Text>
</View>
<Text style={styles.gpsData}>
{this.calcRow(55,55).bind(this)}
</Text>
</View>
</View>
);
});
}
render = ()=> {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return(
<View>
{this.renderGPSDataFromServer()}
</View>
)
}};
How do I go about fixing this and in this case what is the problem?
this.props are read-only
React docs - component and props
And therefore a component shouldn't try a to modify them let alone mutate them as you are doing here:
_buttonPress = () => {
this.props.navigator.push({
id: 'Main'
})
}
I'd suggest using state instead:
_buttonPress = () => {
this.setState = {
...this.state,
navigator: {
...this.state.navigator,
id: 'Main'
}
}
}
Regarding your binding issue:
the .map method takes a 2nd argument that is used to set the value of this when the callback is invoked.
In the context of your question, you just need to pass thisas the 2nd argument to you .map method to bind the components scope's this to it.
This is happening because, the function inside the map method creates a different context. You can use arrow functions as the callback in the map method for lexical binding. That should solve the issue you are having.
renderGPSDataFromServer =() => {
const {loaded} = this.state;
const {state} = this.state;
return this.state.dataArr.map((data, i) => {
return(
<View style={[styles.cardContainer, styles.modularBorder, styles.basePadding]} key={i}>
<View style={styles.cardContentLeft}>
<TouchableHighlight style={styles.button}
onPress={this._buttonPress().bind(this)}>
<Text style={styles.restData}>View Video</Text>
</TouchableHighlight>
</View>
<View style={styles.cardContentRight}>
<Text style={styles.restData}>{i}</Text>
<View style={styles.gpsDataContainer}>
<Text style={styles.gpsData}>
{Number(data.lat).toFixed(2)}</Text>
<Text style={styles.gpsData}>{Number(data.long).toFixed(2)}</Text>
</View>
<Text style={styles.gpsData}>
{this.calcRow(55,55).bind(this)}
</Text>
</View>
</View>
);
});
}
Also, once you've used arrow functions in the class function definition you
don't need to bind them in constructor like:
constructor(props) {
super(props);
this._customMethodDefinedUsingFatArrow = this._customMethodDefinedUsingFatArrow.bind(this)
}
Also, once you have defined class functions as arrow functions, you
don't need to use the arrow functions while calling them either:
class Example extends React.Component {
myfunc = () => {
this.nextFunc()
}
nextFunc = () => {
console.log('hello hello')
}
render() {
// this will give you the desired result
return (
<TouchableOpacity onPress={this.myFunc} />
)
// you don't need to do this
return (
<TouchableOpacity onPress={() => this.myFunc()} />
)
}
}
not sure if this is the problem, but I think is code is wrong, and may be potentially causing your issue.
<View style={styles.cardContentLeft}>
<TouchableHighlight style={styles.button}
onPress={this._buttonPress().bind(this)}>
<Text style={styles.restData}>View Video</Text>
</TouchableHighlight>
</View>
specifically this line onPress={this._buttonPress().bind(this)}>
you are invoking the function and binding it at the same time.
The correct way to do this would be so
onPress={this._buttonPress.bind(this)}>
this way the function will be called only onPress.
You are going in the right direction, but there is still a minor issue. You are passing a function to your map callback that has a different scope (this) than your component (because it is not an arrow function), so when you do bind(this), you are rebinding your callback to use the scope from map. I think this should work, it basically turns the callback that you pass to map into an arrow function. Also, since you bind your function in the constructor, you do not need to do it again:
// The constructor logic remains the same
// ....
renderLoadingView() {
return (
<View style={[styles.cardContainer, styles.loading]}>
<Text style={styles.restData}>
Loading ...
</Text>
</View>
)
}
_buttonPress = () => {
this.props.navigator.push({
id: 'Main'
})
}
renderGPSDataFromServer =() => {
const {loaded} = this.state;
const {state} = this.state;
return this.state.dataArr.map((data, i) => {
return(
<View style={[styles.cardContainer, styles.modularBorder, styles.basePadding]} key={i}>
<View style={styles.cardContentLeft}>
<TouchableHighlight style={styles.button}
onPress={this._buttonPress}>
<Text style={styles.restData}>View Video</Text>
</TouchableHighlight>
</View>
<View style={styles.cardContentRight}>
<Text style={styles.restData}>{i}</Text>
<View style={styles.gpsDataContainer}>
<Text style={styles.gpsData}>
{Number(data.lat).toFixed(2)}</Text>
<Text style={styles.gpsData}>{Number(data.long).toFixed(2)}</Text>
</View>
<Text style={styles.gpsData}>
{this.calcRow(55,55).bind(this)}
</Text>
</View>
</View>
);
});
}
render = ()=> {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return(
<View>
{this.renderGPSDataFromServer()}
</View>
)
}};

Categories