I have added a function to disable the back button press in particular screen on my app. after the I have gone away from this screen back button is disabled in the whole app. The back button is disabled after that. following is my code
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
(async () => {
// console.log('param name.....',itemId)
const time = await AsyncStorage.getItem('#timer_set')
setEndTime(time);
const backhandler = BackHandler.addEventListener('hardwareBackPress', () => {
return true;
});
return () => {
backhandler.remove();
};
})();
});
return unsubscribe;
}, [navigation]);
Use BackHandler.removeEventListener.
useEffect(() => {
const backButtonHandler = () => {
return true;
}
BackHandler.addEventListener("hardwareBackPress", backButtonHandler);
return () =>
BackHandler.removeEventListener("hardwareBackPress", backButtonHandler);
}, []);
I am trying to disable android back button on home screen only.
My code:
React.useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackBtnPressed);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackBtnPressed);
}
}, [])
const handleBackBtnPressed = () => {
navigation.goBack(null);
return true
}
const navigateToNextScreen = () => {
navigation.push('Prmotions');
}
If I remove navigation.goBack(null); back button is disabled for all screen and with above code back button is not disabled at all.
navigation.navigate("ScreenName") isn't working for mu scenario to move to next screen that's why I have used navigation.push
I handled it by putting this on all screens where I wanted to go back on back button press.
React.useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackBtnPressed);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackBtnPressed);
}
}, [])
const handleBackBtnPressed = () => {
navigation.goBack(null);
return true
}
and put this where I wanted not to go back.
React.useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackBtnPressed);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackBtnPressed);
}
}, [])
const handleBackBtnPressed = () => {
return true
}
I know this might not be best solution but it worked for me pretty well.
I am a beginner in react native and very confused about navigation between two screens after x second delay.
How can I move from splash screen to login screen after some seconds in react native?
this is how iv'e achieved that by having a splashscreen as inital route in stackNavigator and then in componentDidMount after 3 secs im navigating to LoginScreen.
{
initialRouteName: "SplashScreen"
}
this is inside the stack navigator.
and inside the componentDidMount of the splashScreen class im doing this
componentDidMount(){
window.setTimeout(async () => {
const token = await isSignedIn();
this.props.navigation.navigate(token ? 'HomeScreen' : 'OnBoardingScreen');
}, 3000);
}
so what im doing is, im checking if token is stored in asyncStorage by the isSignedIn(). and if token is present then im navigating to HomeScreen or LoginScreen respectively after 3 secs.(3000 denotes in ms)
Feel free for doubts.
UPDATE:
import React, { Component } from 'react';
import { View, StatusBar } from 'react-native';
import { isSignedIn } from '../../services/auth';
import Animation from "lottie-react-native";
import styles from './SplashScreenStyle';
export default class SplashScreen extends Component {
componentDidMount() {
StatusBar.setHidden(true);
this._playAnimation();
window.setTimeout(async () => {
const token = await isSignedIn();
this.props.navigation.navigate(token ? 'HomeScreen' : 'OnBoardingScreen');
}, 2120);
}
state = {
animation: null,
};
_playAnimation = () => {
if (!this.state.animation) {
this._loadAnimationAsync();
} else {
this.animation.play();
}
};
_loadAnimationAsync = async () => {
let result = await fetch(
"https://assets1.lottiefiles.com/packages/lf20_vi3n1R.json"
)
.then(data => {
return data.json();
})
.catch(error => {
console.error(error);
});
this.setState({ animation: result }, this._playAnimation);
};
render() {
return (
<View style={styles.animationContainer}>
{this.state.animation && (
<Animation
ref={animation => {
this.animation = animation;
}}
style={{ width: 200, height: 200, backgroundColor: "transparent" }}
source={this.state.animation}
/>
)}
</View>
);
}
}
I wish to utilize an in-app notification system, aka a more attractive and less in your face' use of alerts to let the user know what actions are being done, especially when for instance a barcode has been detected but it needs to send that barcode to the server and the user needs to wait.
I have found this lib and have attempted to implement it; but as I am using React Navigation and I wish to render the item at the very top of the application, it gets cut off by React Native header
Is it possible to have a function I can create and reference whenever I want a global notification and it will render on the very top I would imagine it would need to render here:
import React from 'react';
import { createBottomTabNavigator,createStackNavigator } from 'react-navigation';
import SearchTab from './components/Tabs/SearchTab';
import HomeTab from './components/Tabs/HomeTab';
import ScannerTab from './components/Tabs/ScannerTab';
import SettingsTab from './components/Tabs/SettingsTab';
import Ionicons from 'react-native-vector-icons/Ionicons';
import StockModal from './components/Modals/StockModal';
const MainStack = createBottomTabNavigator(
{
Home: HomeTab,
Search: SearchTab,
Scanner: ScannerTab,
Settings: SettingsTab,
//Todo: Total overlay modals HERE
},
{
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'Home') {
iconName = `ios-information-circle${focused ? '' : '-outline'}`;
} else if (routeName === 'Settings') {
iconName = `ios-options${focused ? '' : '-outline'}`;
}else if (routeName === 'Scanner') {
iconName = `ios-barcode${focused ? '' : '-outline'}`;
}else if (routeName === 'Search') {
iconName = `ios-search${focused ? '' : '-outline'}`;
}
return <Ionicons name={iconName} size={25} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
}
);
export default RootStack = createStackNavigator(
{
Main: {
screen: MainStack,
},
QuickStockScreen: {
screen: StockModal,
},
},
{
mode: 'modal',
headerMode: 'none',
}
);
But even if that's possible, I am not sure how its possible to build a function that tells the notification to show; React Redux comes to mind but I don't wish to implement such a cumbersome system just for one feature and it was something I considered when creating his application and decided against.
The notification system in question (not very clear documentation or examples sadly) https://www.npmjs.com/package/react-native-in-app-notification
Here is the navigation lib I am using: https://reactnavigation.org/
What you want would be a component that is a the same level of the navigation (So it can display over it). In multiple projects, I use react-native-root-siblings to do so. It allows you to add UI over the app and so over the navigation.
An exemple how what I made with it. The dark layer and the box at the bottom are part of the Siblings Component.
https://gyazo.com/7ad3fc3fea767ea84243aaa493294670
The Siblings is used like the Alert of React-Native, so as a function (which is quite useful!)
messageMenu.js
import React, { Component } from 'react';
import RootSiblings from 'react-native-root-siblings';
import MessageMenuContainer from './MessageMenuContainer';
export default class Dialog extends Component {
static show = (props) => new RootSiblings(<MessageMenuContainer {...props} />);
static update = (menu, props) => {
if (menu instanceof RootSiblings) {
menu.update(<MessageMenuContainer {...props} />);
} else {
console.warn(`Dialog.update expected a \`RootSiblings\` instance as argument.\nBut got \`${typeof menu}\` instead.`);
}
}
static close = (menu) => {
if (menu instanceof RootSiblings) {
menu.destroy();
} else {
console.warn(`Dialog.destroy expected a \`RootSiblings\` instance as argument.\nBut got \`${typeof menu}\` instead.`);
}
}
render() {
return null;
}
}
export {
RootSiblings as Manager,
};
Where the MessageMenuContainer is your component to render at the top.
Component using the Root Siblings:
import React from 'react';
import PropTypes from 'prop-types';
import I18n from 'react-native-i18n';
import { BackHandler, Keyboard, Platform, TouchableOpacity } from 'react-native';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import DraftMenu from './messageMenu'; //HERE IS THE IMPORT YOU WANT
import { Metrics, Colors, Fonts } from '../../main/themes';
class DraftBackButton extends React.Component {
state = {
draftMenu: undefined,
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackAndroid);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackAndroid);
}
handleBackAndroid = () => {
this.handleBack();
return true;
}
handleBack = async () => {
Keyboard.dismiss();
await this.openDraftMenu();
}
openDraftMenu = async () => {
if (this.state.draftMenu) {
await DraftMenu.update(this.state.draftMenu, this.draftMenuProps());
} else {
const draftMenu = await DraftMenu.show(this.draftMenuProps());
this.setState({ draftMenu: draftMenu });
}
}
draftMenuProps = () => ({
options: [
{ title: I18n.t('message.deleteDraft'), onPress: this.deleteDraft, icon: 'trash' },
{ title: I18n.t('message.saveDraft'), onPress: this.saveOrUpdateDraft, icon: 'documents' },
{ title: I18n.t('cancel'), icon: 'close', style: { backgroundColor: Colors.tertiaryBackground } },
],
destroyMenuComponent: async () => {
DraftMenu.close(this.state.draftMenu);
await this.setState({ draftMenu: undefined });
},
withIcon: true,
})
saveOrUpdateDraft = async () => {
// SAVE OR UPDATE DRAFT. NOT IMPORTANT
}
saveDraft = async () => {
// SAVING THE DRAFT
}
updateDraft = async () => {
// UPDATING THE DRAFT
}
deleteDraft = async () => {
// DELETING THE DRAFT
}
render() {
return (
<TouchableOpacity
hitSlop={Metrics.touchable.largeHitSlop}
onPress={() => {
this.handleBack();
}}
>
<Text>BUTTON</Text>
</TouchableOpacity>
);
}
}
DraftBackButton.propTypes = {
// ALL THE PROPTYPES
};
function mapStateToProps(state, ownProps) {
//
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({ fetchMessages }, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(DraftBackButton);
The best thing with this lib is that you can call the .show anywhere in your app and it will render at the very top!
Hope it's what you're looking for!
EDIT:
I updated the example of how to use the Root Siblings.
Here's the content of my MessageContainer which will be display on top of everything
import React from 'react';
import PropTypes from 'prop-types';
import { Animated, Dimensions, InteractionManager, StyleSheet, TouchableOpacity, View } from 'react-native';
import MessageMenuItem from './MessageMenuItem';
import { Colors } from '../../../main/themes';
const { width, height } = Dimensions.get('window');
const OPTION_HEIGHT = 55;
const OVERLAY_OPACITY = 0.5;
export default class DraftMenuContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
animatedHeight: new Animated.Value(0),
animatedOpacity: new Animated.Value(0),
menuHeight: props.options.length * OPTION_HEIGHT,
};
}
componentDidMount() {
this.onOpen();
}
// Using Animated from react-native to make the animation (fade in/out of the dark layer and the dimensions of the actual content)
onOpen = async () => {
await this.state.animatedHeight.setValue(0);
await this.state.animatedOpacity.setValue(0);
Animated.parallel([
Animated.timing(this.state.animatedHeight, { toValue: this.state.menuHeight, duration: 200 }),
Animated.timing(this.state.animatedOpacity, { toValue: OVERLAY_OPACITY, duration: 200 }),
]).start();
}
onClose = async () => {
await this.state.animatedHeight.setValue(this.state.menuHeight);
await this.state.animatedOpacity.setValue(OVERLAY_OPACITY);
Animated.parallel([
Animated.timing(this.state.animatedHeight, { toValue: 0, duration: 200 }),
Animated.timing(this.state.animatedOpacity, { toValue: 0, duration: 200 }),
]).start(() => this.props.destroyMenuComponent()); // HERE IS IMPORTANT. Once you're done with the component, you need to destroy it. To do so, you need to set a props 'destroyMenuComponent' which is set at the creation of the initial view. See the other code what it actually do
}
render() {
return (
<View style={styles.menu}>
<Animated.View style={[styles.backgroundOverlay, { opacity: this.state.animatedOpacity }]}>
<TouchableOpacity
activeOpacity={1}
onPress={() => this.onClose()}
style={{ flex: 1 }}
/>
</Animated.View>
<Animated.View style={[styles.container, { height: this.state.animatedHeight }]}>
{this.props.options.map((option, index) => (
<MessageMenuItem
height={OPTION_HEIGHT}
icon={option.icon}
key={index}
onPress={async () => {
await this.onClose();
InteractionManager.runAfterInteractions(() => {
if (option.onPress) {
option.onPress();
}
});
}}
style={option.style}
title={option.title}
withIcon={this.props.withIcon}
/>
))}
</Animated.View>
</View>
);
}
}
DraftMenuContainer.propTypes = {
destroyMenuComponent: PropTypes.func.isRequired,
withIcon: PropTypes.bool,
options: PropTypes.arrayOf(PropTypes.shape({
icon: PropTypes.string.isRequired,
onPress: PropTypes.func,
title: PropTypes.string.isRequired,
})),
};
I am currently trying to learn React Native, but I already struggle in the Networking Part of the Tutorial.
This is the code:
import React, { Component } from 'react';
import { AppRegistry, Text, TextInput, View } from 'react-native';
class App extends Component {
function getMoviesFromApiAsync() {
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
return responseJson.movies;
})
.catch((error) => {
console.error(error);
});
}
render() {
getMoviesFromApiAsync();
};
}
AppRegistry.registerComponent('testproject', () => App);
And I get the following error:
In my case Line 5, Char 10 would be: function so it expects something else after funct.
Here is an example of using that function:
import React, { Component } from 'react';
import { AppRegistry, Text, TextInput, View } from 'react-native';
class App extends Component {
constructor(props) {
super(props);
this.state = { movies: [] }
}
componentDidMount() {
this.getMoviesFromApiAsync();
}
getMoviesFromApiAsync() {
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
this.setState({ movies: responseJson.movies });
})
.catch((error) => {
console.error(error);
});
}
renderMovies = () =>
this.state.movies.map((movie, i) => <Text key={i}>{movie.title}</Text>)
render() {
return (
<View style={{flex: 1}}>
{this.renderMovies()}
</View>
)
};
}
AppRegistry.registerComponent('testproject', () => App);
import React, { Component } from 'react';
import { AppRegistry, Text, TextInput, View } from 'react-native';
class App extends Component {
state = {
movies: null
}
componentDidMount() {
const movies = this.getMoviesFromApiAsync();
this.setState({movies: movies});
}
getMoviesFromApiAsync() {
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
return responseJson.movies;
})
.catch((error) => {
console.error(error);
});
}
render() {
const { movies } = this.state;
if (!movies) return null;
return (
<View>
{
movies.map((movie, index) => {
console.log("movie:", movie);
return(
<View key={index}>
<Text>{movie.name}</Text>
</View>
)
})
}
</View>
)
};
}
AppRegistry.registerComponent('testproject', () => App);
1 - ) So first set variable in state movies null cause u dont have any movies data
2 - ) Read React Component Lifecycle ComponentDidMount run after render and call getMovies func for fetch data and write in the state with this.setState
3 - ) Check u have movies with if(!movies) return null; or return ActivityIndicator for loading but if u dont get movies activity indicator run forever.
4 - ) this.setState render your component again with new state