Integration issues with react-native-gesture-handler on Android
See original GitHub issueI am attempting to use Navigation React Native
as the routing solution for my native app and am liking it quite a bit: performant, simple, intuitive and quite flexible. However, In my early integration attempts (using some of the other core libraries i would be using in my redux-driven app) i find that I have a couple of Android-specific issues when i attempt integration with react-native-gesture-handler
.
Main Issue
The SideDrawer
seems to work only in the initial screen when an attempt is made to trigger it via a gesture (swipe left/right from the edges, depending on the configuration). When i navigate away to another screen that also has the SideDrawer, it does not work. It does work everywhere when i try to programmatically open/close, regardless of which screen i am on, however.
Secondary Issue
Additionally a minor issue was noticed as well. Running back actions, both via an app button and via the hardware back button, seem to flash the side drawer for about a second before navigation. It seems like it is navigating 2 steps instead of 1 with the flashing drawer seeming to visually appear as an intermediary screen.
Note: Everything works perfectly fine in IoS however.
I use the SideDrawer as an HOC, wrapping screens that would require the SideDrawer but have attempted using it normally as well.
The installation docs for react-native-gesture-handler
has a section dedicated to installation for android apps that use native navigation libraries. Essentially they require wrapping each screen with a dedicated HOC shipped with the library.
As far i understand Navigation
has a single ReactRoot(a recent change) and so, if wrapping is necessary, it can be done at the topmost level. I tried that but It didn’t work. I also attempted wrapping individual screens but with no success. Ive used the gesture handler library in other apps, both JS-driven(react-navigation
, no change was necessary) and native (react-native-navigation, with integration of the specific changes required as was documented) and they work fine. My guess is i might perhaps be needing the wrapping of the dedicated HOC shipped with react-native-gesture-handler since, as per the installation docs for Navigation
on React Native, there is specific mention of the use of native APIs for navigation:
The Navigation router for React Native uses the underlying native APIs to provide faithful navigation on Android and iOS.
My current minimal package.json:
{
"name": "menuappnative",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"@react-native-community/async-storage": "^1.5.1",
"@react-native-community/netinfo": "^4.0.0",
"navigation": "^5.2.0",
"navigation-react": "^4.1.1",
"navigation-react-native": "^5.3.0",
"prop-types": "^15.7.2",
"react": "16.8.3",
"react-native": "0.59.10",
"react-native-device-info": "^2.2.2",
"react-native-firebase": "^5.5.5",
"react-native-gesture-handler": "^1.3.0",
"react-native-vector-icons": "^6.6.0",
"react-redux": "^7.1.0",
"redux": "^4.0.3",
"redux-thunk": "^2.3.0"
},
"devDependencies": {
"@babel/core": "^7.5.4",
"@babel/runtime": "^7.5.4",
"babel-jest": "^24.8.0",
"jest": "^24.8.0",
"metro-react-native-babel-preset": "^0.55.0",
"react-test-renderer": "16.8.3"
},
"jest": {
"preset": "react-native"
}
}
The App.js:
import React from 'react';
import { StateNavigator } from 'navigation';
import { NavigationHandler } from 'navigation-react';
import { NavigationStack } from 'navigation-react-native';
import { Alert, BackHandler } from 'react-native';
import { Provider } from 'react-redux';
import Menu from './Menu';
import store from './src/redux/store';
import Welcome from './Welcome';
const stateNavigator = new StateNavigator([
{key: 'welcome', trackCrumbTrail: true},
{key: 'menu', trackCrumbTrail: true},
]);
const {welcome,menu} = stateNavigator.states;
welcome.renderScene = () => <Welcome />;
menu.renderScene = () => <Menu />;
stateNavigator.navigate('welcome');
class App extends React.Component{
componentDidMount(){
BackHandler.addEventListener("hardwareBackPress",this._handleHardwareBackPress)
}
componentWillUnmount(){
BackHandler.removeEventListener("hardwareBackPress",this._handleHardwareBackPress)
}
_handleHardwareBackPress=(args)=>{
if(!stateNavigator.canNavigateBack(1)){
Alert.alert("Show a prompt with OK/CANCEL")
return true
}
}
render(){
return(
<Provider store={store}>
<NavigationHandler stateNavigator={stateNavigator}>
<NavigationStack />
</NavigationHandler>
</Provider>
);
}
}
export default App;
The Welcome screen:
import React, { Component } from 'react';
import { NavigationContext } from 'navigation-react';
import { Button, SafeAreaView, StyleSheet, Text } from 'react-native';
import { connect } from 'react-redux';
//import SideDrawer from './src/modules/SideDrawer/SideDrawer';
import withSideDrawer from './src/helpers/hoc/withSideDrawer';
class Welcome extends Component {
_onPress = (stateNavigator) => {
stateNavigator.navigate('menu');
}
render() {
return (
<NavigationContext.Consumer>
{({stateNavigator}) => (
<SafeAreaView style={styles.container}>
<Text>
Welcome
</Text>
<Button title="To Menu Screen" onPress={() => this._onPress(stateNavigator)}/>
</SafeAreaView>
)}
</NavigationContext.Consumer>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E91E63'
},
});
const mapStateToProps = (state) => {
return {common: state.commonReducer,
nav: state.navigationReducer}
}
export default connect(mapStateToProps)(withSideDrawer(Welcome));
The Menu Screen
import { NavigationContext } from 'navigation-react';
import React, { Component } from 'react';
import { Button, SafeAreaView, StyleSheet, Text } from 'react-native';
import { connect } from 'react-redux';
import withSideDrawer from './src/helpers/hoc/withSideDrawer';
class Menu extends Component {
_onPress = (stateNavigator) => {
stateNavigator.navigateBack(1);
}
render() {
return (
<NavigationContext.Consumer>
{({stateNavigator}) => (
<SafeAreaView style={styles.container}>
<Text>
Menu
</Text>
<Button title="Back" onPress={() => this._onPress(stateNavigator)}/>
</SafeAreaView>
)}
</NavigationContext.Consumer>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E91E63'
},
});
const mapStateToProps = (state) => {
return {common: state.commonReducer, nav: state.navigationReducer}
}
export default connect(mapStateToProps)(withSideDrawer(Menu));
Issue Analytics
- State:
- Created 4 years ago
- Comments:35 (35 by maintainers)
Routing in Next.js is an underwhelming implementation of a nice idea. I wrote about how they can get rid of nested files and still keep their file-based approach
This is great news and perfect timing as well for me. My current project is scoped rather large at the moment: a PWA solution (with
navigation-react
powering the routing) as well as native Android/Ios apps. I went amonorepo
route for all the benefits it affords and found that thenavigation
suite of packages is the only routing solution out there that could handle routing requirements across the device landscape (thus my projects landscape) via the same monorepo philosophy of shared packages and cohesive residency while following a uniform approach all through. Less stress/fatigue and better productivity when a suite of products follow a common methodology.Due to some project requirement changes - as recent as the last couple of days - i had to basically go back to using
Nextjs
for my PWA which meant that i had to dropnavigation-react
. Its a trade-off with a lot of factors weighing in and the decision came after considerable thought.However,
navigation-react-native
is the decided solution for my mobile apps. in fact i had already installed it in my monorepo even before starting out on thereact-native
project 😃 I like its unique approach and the fact that the navigation is native makes it a perfect optimal routing solution. Leaving aside the easy routing and now the drawer improvements, i would have chosennavigation-react-native
just for itstabs
.