I have been searching for a solution for a long time, but surprisingly, I think nobody has faced it yet. So I am posting it.
I have created a simple Drawer Navigator with React Navigation V3. I have added a Menu icon, and when I click it, the drawer appears as it should be. But, no hand gesture is working. Swiping from left to right don't do anything. Even when the drawer is open, tapping on empty space doesn't close the drawer.
Here is my code:
import {
createStackNavigator,
createSwitchNavigator,
createAppContainer,
createDrawerNavigator
} from 'react-navigation';
import Home from './screens/Home';
import LoginForm from './screens/LoginForm';
import Articles from './screens/Articles';
const AuthStack = createStackNavigator({
LoginScreen: LoginForm
});
const AppStack = createDrawerNavigator({
HomeScreen: Home,
ArticlesScreen: Articles
});
const RootNavigator = createSwitchNavigator(
{
Auth: AuthStack,
App: AppStack
},
{
initialRouteName: 'Auth'
}
);
export default createAppContainer(RootNavigator);
I have found the solution. React Navigation depends on the react-native-gesture-handler library. In the Installation section of React Navigation docs, it only says to create link by using the command react-native link. This is enough for iOS. But for Android, you have to edit the MainActivity.java file, so that the gesture handler library can work as expected:
import com.facebook.react.ReactActivity;
+ import com.facebook.react.ReactActivityDelegate;
+ import com.facebook.react.ReactRootView;
+ import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
public class MainActivity extends ReactActivity {
#Override
protected String getMainComponentName() {
return "Example";
}
+ #Override
+ protected ReactActivityDelegate createReactActivityDelegate() {
+ return new ReactActivityDelegate(this, getMainComponentName()) {
+ #Override
+ protected ReactRootView createRootView() {
+ return new RNGestureHandlerEnabledRootView(MainActivity.this);
+ }
+ };
+ }
}
Refer to the documentation: https://kmagiera.github.io/react-native-gesture-handler/docs/getting-started.html
Actually, it's nowhere stated in React Navigation documentation to modify any files, as it is specific to react-native-gesture-handler and not React Navigation. I am keeping the answer here so it may help others.
UPDATE: The latest docs of React Navigation addresses this issue
In the index.js of your project just use gestureHandlerRootHOC:
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
import { gestureHandlerRootHOC } from 'react-native-gesture-handler'
AppRegistry.registerComponent(appName, () => gestureHandlerRootHOC(App));
resource: https://github.com/react-navigation/drawer/issues/105#issuecomment-540667009
Update:
In React Navigation > 5.x
Just put react-native-gesture-handler at the beginning of root index.js
import 'react-native-gesture-handler';
Seems to be fixed in versions above 0.61.0, but for older versions this worked for me.
In the index.js :
. . .
import {gestureHandlerRootHOC} from 'react-native-gesture-handler';
AppRegistry.registerComponent(appName, () => gestureHandlerRootHOC(App));
. . .
React native docs updated this issue and you can find a section named Installing dependencies into a bare React Native project in the below link
https://reactnavigation.org/docs/en/getting-started.html#installation
Related
App.js:
import React, { Component } from 'react';
import {View,Text} from 'react-native';
import { createDrawerNavigator } from 'react-navigation-drawer';
import {createAppContainer} from 'react-navigation';
import Epics from './screens/tmp';
import Pager from './screens/Pager';
const DrawerNavigator = createDrawerNavigator({
Home: {screen: Epics},
Page: {screen: Pager}
},{initialRouteName: 'Home'});
const Stack = createAppContainer(DrawerNavigator);
export default class App extends Component {
render() {
return <Stack />;
}
}
Trying to invoke fetch API everytime a user lands on screen using navigation addListner event
componentDidMount() {
this.loadFeed(); // fetch API
const { navigation } = this.props;
this.focus = navigation.addListener('willFocus', () => {
this.loadFeed(); // fetch API
});
}
React Navigation version from package.json:
"react-navigation": "^4.2.2"
"react-navigation-drawer": "^2.4.2"
Is there a better way to detect an active screen on app and invoke the fetch API? Or fix for the given error below?
Type Error: undefined is not an object (evaluating 'navigation.addListner'):
Error when the app launches
Update
I am trying to replicate following example in snack: https://snack.expo.io/HkrP8YPIf
What am I doing wrong? (I am new to React Native, please help me understand)
Try using the NavigationEvents component shipped with react-navigation 4.x. Just nest it anywhere inside your screen's render method.
Example:
import React from 'react';
import { View } from 'react-native';
import { NavigationEvents } from 'react-navigation';
const MyScreen = () => (
<View>
<NavigationEvents
onWillFocus={() => console.log('Screen will be in focus')}
onDidFocus={() => console.log('Screen is in focus')}
onWillBlur={() => console.log('Screen will blur')}
onDidBlur={() => console.log('Screen blurred')}
/>
{/*
other code
*/}
</View>
);
export default MyScreen;
This just means that navigation doesn't exist. So it looks like the component is supposed to receive it via props and isn't. That's all I can tell from this code.
Check your props keys, agree with James. Have one suggestion here, since you're expecting a props, you should handle this common error whether key exist or not(if else)
I am trying du use react-native-contacts with a react-native app made with Expo, but I have this error message :
undefined is not an object (evaluating '_reactNativeContacts.default.getAll')
Here is the code I use :
import React from 'react';
import {
Image,
Platform,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
Modal,
TouchableHighlight,
ImageBackground,
TextInput,
Picker,
PermissionsAndroid
} from 'react-native';
import { WebBrowser } from 'expo';
import Contacts from 'react-native-contacts';
import { MonoText } from '../components/StyledText';
Contacts.getAll((err, contacts) => {
if (err === 'denied'){
// error
} else {
// contacts returned in Array
}
})
I tried to follow all he steps for the installation in this page for the android part :
https://github.com/rt2zz/react-native-contacts#getting-started
But I don't find where I can do this part :
I don't know where I can find this file : android/settings.gradle
By the way I tried this command "react-native link" in my app directory and nothing changed.
Android
In android/settings.gradle
...
include ':react-native-contacts'
project(':react-native-contacts').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-contacts/android')
In android/app/build.gradle
...
dependencies {
...
implementation project(':react-native-contacts')
}
Has anyone had this kind of problem ?
Thanks for help !
As far as I understand, you are developing your app with Expo. Some of independent libraries doesn't work well with Expo. I have two suggestions for you.
If you want to keep using react-native-contacts, you need to eject your app from Expo
Or directly use Expo's contacts api, You can find the details in this link Expo's Contacts I would do this which is less work for you to do and solve your problem
import { Contacts } from 'expo';
const { data } = await Contacts.getContactsAsync({
fields: [Contacts.Fields.Emails],
});
if (data.length > 0) {
const contact = data[0];
console.log(contact);
}
You can find same issue created in react-native-contacts github page . Issue
July 2021 update
The Contacts module has been moved from the core expo package to expo-contacts (see documentation).
Example:
import * as Contacts from 'expo-contacts';
const { status } = await Contacts.requestPermissionsAsync();
if (status === 'granted') {
const { data: contacts } = await Contacts.getContactsAsync();
console.log('Retrieved contacts!', contacts);
}
I am trying to implement stacknavigation using react-navigation. When I am creating a stacknavigation const and calling in my default screen it is giving me this error.
Route 'Main' should declare a screen. For example:
import MyScreen from './MyScreen';
...
Home: {
screen: MyScreen,
}
My StackNavigation code is here
import React from 'react';
import {View, Text } from 'react-native';
import Register from './Register';
import Main from './Main';
import { StackNavigator } from 'react-navigation';
const ScreenList = StackNavigator({
Main: {
screen: Main,
},
Register: {
screen: Register,
},
});
export default ScreenList;
And this is the main and default screen
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { Card, Button, CardSection } from '../components/common/Index';
import Login from '../components/Login';
import ScreenList from './ScreenList';
export default class Main extends Component {
render() {
return (
<View>
<Button>Register</Button>
</View>
);
}
}
This is an issue with react-native-navigation not yet being compatible with React 0.52.0
More information on this issue can be found on this specific issue tracked on Github.
Edit: a quick fix I just implemented to unblock myself while the project contributors figure out a solid solution was to add the missing interface (ReactInstanceDevCommandsHandler.java) directly into my react-native-navigation project.
I am new to react native and having issues importing basic component into the index.android.js file. I could not find what was wrong and also couldn't find posts on this specific issue. Please help what is wrong.
Error says: Unexpected Token near CounterComponent.android.js line 7. Marked it with **.
import React, { Component } from 'react';
import { AppRegistry, ListView, Text, View } from 'react-native';
export default class Counter extends Component {
render() {
return{
**<View>**
<Text>Counter component</Text>
</View>
};
}
}
Imported the file using command below in the index.android.js
import Counter from './app/components/CounterComponent'
Try replacing your { for ( after the return, something like this:
import React, { Component } from 'react';
import { AppRegistry, ListView, Text, View } from 'react-native';
export default class Counter extends Component {
render() {
return (
<View>
<Text>Counter component</Text>
</View>
);
}
}
I'm following the tutorial from meteor and angular 2 and when I reach the step 11 Running your app on Android or iOS with PhoneGap I can't make it work on my android device.
This is the output I get from the console.
Error: Uncaught (in promise): Error: Error in ./AppComponent class AppComponent_Host - inline template:0:0 caused by: The selector "app" did not match any elements
This is what I have so far in my app.component.ts file:
import { Component } from '#angular/core';
import template from './app.component.html';
#Component({
selector: 'app',
template
})
export class AppComponent {}
The app works perfectly on the web browser. I think that can be a problem with the router, but I'm not quite sure.
This is the code from the app.routes.ts
import { Route } from '#angular/router';
import { Meteor } from 'meteor/meteor';
import { PartiesListComponent } from '../parties/parties-list.component';
import { PartyDetailsComponent } from '../parties/party-details.component';
export const routes: Route[] = [
{ path: '', component: PartiesListComponent },
{ path: 'party/:partyId', component: PartyDetailsComponent}
];
This is the index.html:
<head>
<base href="/" />
</head>
<body>
<app>Loading...</app>
</body>
And this is the app.component.html
<div>
<router-outlet></router-outlet>
</div>
It is supossed to redirect to the PartiesListComponent but just throw that error and stucks on loading. Thank you.
SOLVED
This is the original code in the main.ts (Extracted from the website of the tutorial)
import 'angular2-meteor-polyfills';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './imports/app/app.module';
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
I've just find that this tutorial is obsolete (again) and there's a new way to bootstrap applications.
With the next code the app works fine on android.
import 'angular2-meteor-polyfills';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { enableProdMode } from '#angular/core';
import { Meteor } from "meteor/meteor";
import { AppModule } from './imports/app/app.module';
enableProdMode();
Meteor.startup(() => {
platformBrowserDynamic().bootstrapModule(AppModule);
});
I hope this help someone.