Clear Interval when app is in background state in React Native - reactjs

I would like to know how to clear an Interval whenever my app goes into Background State.
Sometimes when I click the Home button my application is being closed (willUnmount event is not fired) and then the interval is never cleared.

How did you know the interval is never cleared if app closed?(Just curious) If App is being closed, it should be not working at all, isn't it? Only if you have background timer maybe will run?
But I think it should be stopped if you close the app?
I think in your case, you can use AppState from react-native, to detect if app went back to foreground then reset the interval?
import React, {
Component
} from "react";
import {
AppState,
StyleSheet,
Text,
View
} from "react-native";
export default class AppStateExample extends Component {
state = {
appState: AppState.currentState
};
componentDidMount() {
AppState.addEventListener("change", this._handleAppStateChange);
}
componentWillUnmount() {
AppState.removeEventListener("change", this._handleAppStateChange);
}
_handleAppStateChange = nextAppState => {
if (
this.state.appState.match(/inactive|background/) &&
nextAppState === "active"
) {
console.log("App has come to the foreground!"); //reset interval here
}
this.setState({
appState: nextAppState
});
};
render() {
return (
<View style = {
styles.container
} >
<Text>
Current state is: {
this.state.appState
}</Text>
</View >
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center"
}
});

Related

No safe area insets value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app. - how can i ressolve this error?

export default class CalorieScreen extends Component {
constructor() {
super();
this.state = { text: "" };
}
render() {
const { calories } = this.state;
return (
<View style={styles.container}>
<Header
backgroundColor={"#9c8210"}
centerComponent={{
text: "Monkey Chunky",
style: { padding: 100, color: "#fff", fontSize: 20 },
}}
/>
</View>
);
}
}
I created a login screen that goes into my calorie screen when i click the buttun it takes me to the screen but this error appears
Make sure you are rendering <SafeAreaProvider> at the top of your app. Something like this.
import { SafeAreaProvider } from 'react-native-safe-area-context';
...
return <SafeAreaProvider>...</SafeAreaProvider>;
...
wrapp all the component in SafeAreaProvide in app.js
import { SafeAreaProvider } from 'react-native-safe-area-context';
...
return ...;
As you are using react-native-elements make sure you install version 2.2.1

Using dropdown component in react-navigation throws error when handler is called

I'm trying to use react-navigation with react-native-dropdown in order to have a dropdown in the header to change what is rendered in the view below.
Whenever I try to execute the handler, react-native-dropdown I get the error "undefined is not a function (near'...this.props.data.map')when react-native-dropdown attempts to render again and maps the dropdown using (this.props.data.map((rows, index) => etc.
Below is the code I'm using:
import React, {Component} from "react"
import {Dimensions, ScrollView, StyleSheet, width, View, TouchableOpacity} from "react-native"
import {Images} from "../../theme"
import DropdownMenu from 'react-native-dropdown-menu';
import Pdf from 'react-native-pdf';
import { Header } from "react-native/Libraries/NewAppScreen";
import { connect } from 'react-redux';
import { NavigationActions } from 'react-navigation';
import { drop } from "lodash";
class InformationScreen extends Component {
constructor(props) {
super(props)
var informationScreens = props.global.appConfig.information_screens
var informationScreenTitles = Object.keys(informationScreens)
state = {
informationScreens: informationScreens,
selectedDropdown: informationScreens[0]
}
}
static navigationOptions = ({ navigation }) => {
return {
headerTitle: <DropdownMenu
style={{flex: 1}}
bgColor={'clear'}
tintColor={'#666666'}
activityTintColor={'rgba(2, 122, 255, 1.0)'}
// arrowImg={}
// checkImage={}
// optionTextStyle={{color: '#333333'}}
// titleStyle={{color: '#333333'}}
// maxHeight={300}
handler={(selection, row) => navigation.setParams({'headerTitle': navigation.state.params[selection][row]})}
data={navigation.state.params}
/>
};
};
render() {
return (
<View style={styles.container}>
<Pdf
source={{ uri: "https://someurl.com/dl/sites/default/files/page/2020%20BYU%20Football%20Almanac_3.pdf", cache: true}}
onLoadComplete={(numberOfPages,filePath)=>{
console.log(`number of pages: ${numberOfPages}`);
}}
style={styles.pdf}
/>
</View>
)
}
}
const styles = StyleSheet.create({
image: {
flex: 1,
},
container: {
flex: 1,
justifyContent: 'flex-start',
alignItems: 'center',
marginTop: 25,
},
pdf: {
flex:1,
width:Dimensions.get('window').width,
height:Dimensions.get('window').height,
}
})
function mapStateToProps(state) {
const global = state.get('global');
return { global };
}
export default connect(mapStateToProps)(InformationScreen);
Ray you were absolutely correct, I figured it out about 5 minutes before you posted.
navigation.state.params was valid and the dropdown would populate, however when I would try to setParams, it would change the format of params to a JSON object instead of an array.
This was remedied by putting my array one JSON object deeper so the object still contained the array after setParams was called. I then called that object in the data.
data={navigation.state.params.informationScreens}
Thank you so much for your help, I'll start using StackOverflow more often.
I suspect this.props.data is either not provided or not an array, so this.props.data.map is undefined, and attempting to invoke it will get you an 'undefined is not a function' error. Is navigation.state.params an array?
If you pass data={navigation.state.params || []} does the issue go away?

Customizing react native share message based on app

I am looking at using ReactNative's share component in my app: https://facebook.github.io/react-native/docs/share#share
Is there a way I can customize the message depending on the app the user chooses to share with?
Like I would want to give a shorter message if the user say shares via twitter as opposed to a longer message for a share via email.
Thanks!
Yes, you can, if the user did share you just need to use result.activityType like this to check if it was shared to WhatsApp for example:
result.activityType === 'net.whatsapp.WhatsApp.ShareExtension'
Check this snack https://snack.expo.io/#neydroid/stack-overflow-test
import * as React from 'react';
import { Alert, Button, Text, View, Share, StyleSheet } from 'react-native';
import { Constants } from 'expo';
import AssetExample from './components/AssetExample';
import { Card } from 'react-native-paper';
export default class App extends React.Component {
onShare = async () => {
try {
const result = await Share.share({
message:
'React Native | A framework for building native apps using React',
})
if (result.action === Share.sharedAction) {
if (result.activityType && result.activityType === 'net.whatsapp.WhatsApp.ShareExtension') {
// shared with WhatsApp
Alert.alert(result.activityType);
} else {
// shared
}
} else if (result.action === Share.dismissedAction) {
// dismissed
}
} catch (error) {
alert(error.message);
}
};
render() {
return (
<View style={styles.container}>
<Button title="Something To Share" onPress={this.onShare}>Share</Button>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
}
});

React-navigation to re-render route when parent state changes

I have a page which receives data from a source in specific Intervals and sets them into a state, I show part of that data inside my page, and I have a button which opens another page(via react-navigation) and I want rest of data to be displayed in there, but the problem is, it won't refresh the second page when state of parent changes, below is simplified code:
import React from "react";
import { View, Text, Button } from "react-native";
import { createStackNavigator, createAppContainer, NavigationActions } from "react-navigation";
class HomeScreen extends React.Component {
constructor() {
super();
this.state = { number: 0 };
}
genNumber() {
number = Math.random();
this.setState({ number });
}
componentWillMount() {
setInterval(() => { this.genNumber() }, 1000);
}
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Home Screen</Text>
<Button title="Go" onPress={() => this.props.navigation.navigate('Test', { k: () => this.state.number })} />
</View>
);
}
}
class TestScreen extends React.Component {
constructor() {
super()
this.state = { t: 1 };
}
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Test {this.props.navigation.getParam('k')()}</Text>
</View>
);
}
}
const AppNavigator = createStackNavigator({
Home: {
screen: HomeScreen,
},
Test: {
screen: TestScreen
}
});
export default createAppContainer(AppNavigator);
you are using navigation params to pass data from parent class to child class and you want a reflection of state change in child class but it won't work in it.
For that use Component and pass data as props you immediate reflection of data.
React will not re-render a screen if a data passed to it through parameters changed, unfortunately this is how react navigation works.
To solve it, you can change the way your are passing data between screens.
instead of using navigation parameters use a global state(example redux).
in this case set the number variable to a state in redux,
then select that number in your Test screen and when number changes it will trigger a re-render.

Navigate to completely different screen on React Native

On my React Native app I am initially loading SceneA, which simply displays a text "Click me". When this button is clicked I would like to load a completely different screen (SceneB) that has completely different components.
All the examples that I found online (like the example below) load a scene with exactly the same components, but different values. In my case it is a completely different layout. How can I navigate to that new screen (SceneB)?
It is basically the equivalent to a new Activity on Android, passing some data at the same time. Any pointers will be appreciated.
index.android.js
import React, { Component } from 'react';
import { AppRegistry, Navigator } from 'react-native';
import SceneA from './SceneA';
class ReactNativeTest extends Component {
render() {
return (
<Navigator
initialRoute={{ title: 'My Initial Scene', index: 0 }}
renderScene={(route, navigator) =>
<SceneA
title={route.title}
// Function to call when a new scene should be displayed
loadNewScene={() => {
const nextIndex = route.index + 1;
navigator.push({
title: 'Scene B',
index: nextIndex,
});
}}
/>
}
/>
)
}
}
AppRegistry.registerComponent('ReactNativeTest', () => ReactNativeTest);
SceneA.js
import React, { Component, PropTypes } from 'react';
import { View, Text, TouchableHighlight } from 'react-native';
export default class SceneA extends Component {
render() {
return (
<View>
<Text>Scene A</Text>
<TouchableHighlight onPress={this.props.loadNewScene}>
<Text>Click Me</Text>
</TouchableHighlight>
</View>
)
}
}
SceneA.propTypes = {
loadNewScene: PropTypes.func.isRequired,
};
You handle which components should render in the renderScene function, each scene will have a route.title so you can decide which to render based on that.
renderScene={(route, navigator) =>
if (route.title === 'Scene A') {
return <SceneA navigator={navigator} />
}
if (route.title === 'Scene B') {
return <SceneB navigator={navigator} />
}
}
Then inside your components you're gonna have a function that handles the navigation:
navigateToSceneB = () => {
this.props.navigator.push({
title: 'Scene B'
})
}

Resources