React-Navigation: Route should declare a screen... error - react-native

I am new to react-navigation and I followed the steps on the site, however I get an error saying Route 'Chat' should declare a screen... Below is my code for reference.
import React from 'react';
import {
AppRegistry,
Text,
View,
Button,
} from 'react-native';
import { StackNavigator } from 'react-navigation';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => navigate('Chat')}
title="Chat with Lucy"
/>
</View>
);
}
}
AppRegistry.registerComponent('navigationApp', () => navigationApp);
This is where I believe the error is occurring
const navigationApp = StackNavigator({
Home: { screen: HomeScreen },
Chat: { screen: ChatScreen },
});
class ChatScreen extends React.Component {
static navigationOptions = {
title: 'Chat with Lucy',
};
render() {
return (
<View>
<Text>Chat with Lucy</Text>
</View>
);
}
}

I'm facing the same issue as yours too here.Well, according to my solution,
what i did is I put the line with:
const navigationApp = StackNavigator({
Home: { screen: HomeScreen },
Chat: { screen: ChatScreen },
});
on top part, just above the AppRegistry... line. It should be in the index.android.js file.
And don't forget to include this line at the top of this file too:
import { ChatScreen } from './App';
And according to the tutorial that you're following(i believe it's the same as what i'm following right here), you should have one other file named 'app.js'; which you're referencing in the import line.
contents of 'app.js':
import React from 'react';
import { View, Text } from 'react-native';
export class ChatScreen extends React.Component {
static navigationOptions = {
title: 'Chat with Lucy',
};
render() {
return (
<View>
<Text>Chat with Lucy</Text>
</View>
);
}
}
That's it. However, it depends on the machine and system you're using. I'm using a MacBook pro with a Mac OS Sierra 10.12.6
And the react-native is also a latest version, not sure if there are more recent versions(there are quite a number of updates from time to time).
Try to modify a line/commands , whichever suits to your versions, and read the examples/tutorials carefully. There could be some deprecated functions/unusable codes, etc., due to some updates/ different system environment.
Good Luck!

If you have an index.js for your component or directory, don't forget to add the export there too! (Not that I've ever done that....)
A good article about organizing a project is and the use of index.js: Organizing a React Native Project on Medium

Put navigationOptions into like
{screen: ScreenComponent, navigationOptions: ...your options }

Related

Using react-navigation 3.* how to navigate from screen to same level BottomTabNavigator?

I got react native app with such structure:
./App.js
./screens/AppNavigator.js
./screens/SignInScreen.js
./screens/HomeScreen.js
./screens/FavoritesScreen.js
App.js:
import { createAppContainer } from "react-navigation";
import AppNavigator from './screens/AppNavigator';
const AppContainer = createAppContainer(AppNavigator);
export default class App extends React.Component {
render() {
return (
<View>
<AppContainer/>
</View>
);
}
}
screens/AppNavigator.js:
import { createSwitchNavigator, createBottomTabNavigator } from 'react-navigation';
import SignInScreen from './SignInScreen';
import HomeScreen from './HomeScreen';
import FavoritesScreen from './FavoritesScreen';
const AppBottomTabNavigator = createBottomTabNavigator({
Home: {
screen: HomeScreen
},
Favorites: {
screen: FavoritesScreen
}
},
{
initialRouteName: 'Home',
});
export default createSwitchNavigator(
{
App: AppBottomTabNavigator,
Auth: SignInScreen
},
{
initialRouteName: 'SignInScreen',
}
);
screens/SignInScreen.js:
export default class SignInScreen extends React.Component {
render() {
return (
<View>
<Button title="Continue w/o sing in..." onPress={this.toApp} />
</View>
);
}
toApp = () => {
this.props.navigation.navigate('App'); // from here I try to navigate to Home screen
};
}
And when I try to navigate to HomeScreen from SignInScreen I see white screen instead of HomeScreen, though all other navigation works well.
The problem do not occur if in screens/AppNavigator.js I change createBottomTabNavigator to createSwitchNavigator, got no idea why. A problem also do not appear if in screens/AppNavigator.js I navigate direct to HomeScreen or FavoritesScreen instead of AppBottomTabNavigator.
I found this thread on github, but, as I understand, it's not related for me, because both AppBottomTabNavigator and SignInScreen are childs of AppNavigator.
So, what is weong with my code?
The problem is in de App.js. For some reason you can't put a BottomTabNavitation inside a View Component, so remove. Like this:
export default class App extends React.Component {
render() {
return (
<AppContainer/>
);
}
}
You should also change the parameter initialRoutName in createSwitchNavigator. You have to put the routName, in this case Auth.
export default createSwitchNavigator(
{
App: AppBottomTabNavigator,
Auth: SignInScreen
},
{
initialRouteName: 'Auth',
}
);

React-native with react-navigation: header not showing in screen

I do have a simple React-native app, using react-navigation for navigation. My issue is that for one of the screens the header and title is not showing, even though it is set in navigationOptions:
main.js:
import React from "react";
import { View, Text } from "react-native";
import {
createDrawerNavigator,
createAppContainer,
createStackNavigator
} from "react-navigation";
import ArticleList from "./screens/ArticleList";
import ArticleList2 from "./screens/ArticeList2";
import ArticleWebView from "./screens/ArticleWebView";
// create the Navigator to be used
const Stack = createStackNavigator({
ArticleList: { screen: ArticleList },
ArticleWebView: { screen: ArticleWebView }
});
const Drawer = createDrawerNavigator(
{
Stack: { screen: Stack },
ArticleList2: { screen: ArticleList2 }
},
{
initialRouteName: "Stack"
}
);
// The container for the navigator
const AppContainer = createAppContainer(Drawer);
class App extends React.Component {
render() {
return <AppContainer />;
}
}
export default App;
The ArticleList2 is a very simple component:
import React from "react";
import { View, Text } from "react-native";
import ArticleListComponent from "../components/ArticleListComponent";
class ArticleList2 extends React.Component {
static navigationOptions = {
title: 'Link2'
};
render() {
return (
<View>
<Text>LIst2</Text>
</View>
);
}
}
export default ArticleList2;
However, the title and header are not rendered in the app. Could anybody help please?
DrawerNavigator does not include a header. In order to create a header inside of ArticleList2 you will have to create a new StackNavigator for the component.
You have to think about and plan out the navigation flow of your app.
The Drawer section of the React Navigation documentation is a little lacking, but you can use the same principle as described in the Tab section
A stack navigator for each tab
const ArticleList2Stack = createStackNavigator({
ArticleList2: { screen: ArticleList2 }
});
const Drawer = createDrawerNavigator(
{
Stack: { screen: Stack },
ArticleList2: { screen: ArticleList2Stack }
},
{
initialRouteName: "Stack"
}
);

React navigation. Render extra views on top of navigator

I'm trying to create a React Native app that renders an area with interchangeable screens and fixed view with some additional data/menu. I tried this solution form official React Navigation, but I can't make it work.
import React, { Component } from "react";
import {createStackNavigator} from 'react-navigation';
import { Text, View,} from 'react-native';
import Details from './DetailsScreen';
import MainScreen from './MainScreen';
const RootStack = createStackNavigator({
Main: {screen: MainScreen,
navigationOptions: {
header: null
}
},
Details: {
screen: Details,
},);
class App extends Component {
static router = {
...RootStack.router,
getStateForAction: (action, lastState) => {
return MyStack.router.getStateForAction(action, lastState);
}
};
render() {
const { navigation } = this.props;
return(
<View>
<Text>Foo</Text> //this is rendering
<RootStack navigation={navigation}/> //this is not
</View>);
}
}
export default App;
Article form link suggests that I can wrap object created with createStackNavigator() in a parent View, but it renders only when it is the only thing returned from render(), otherwise it seems to be ignored. Example from link claims that it is possible to "render additional things", but I can't make it work. Is it possible to do this way?
You can try this:
//wrapper.js
function wrapNavigator(Navigator, Wrapper, wrapperProps = {}) {
const WrappedComponent = props => (
<Wrapper { ...props, ...wrapperProps}>
<Navigator {...props} />
</Wrapper>
);
WrappedComponent.router = Navigator.router;
WrappedComponent.navigationOptions = Navigator.navigationOptions;
return WrappedComponent;
};
//app.js
const App = (props) => <View>
<Text>Some text...</Text>
{children}
</View>
export default wrapNavigator(Stack, App);
But this will not work if there are no parent navigator for App component.

Undefined is not an object React Native StackNavigator

I have been trying to get a simple React Native StackNavigation example app working, however I keep getting an
TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate')
I am not expecting the app to navigate anywhere at this stage, simply deploy with an app bar and some arbitrary text.
import React, { Component } from 'react';
import {AppRegistry, Text} from 'react-native';
import {StackNavigator} from 'react-navigation';
export default class App extends React.Component {
static navigationOptions = {
title: 'Home',
};
render() {
const { navigate } = this.props.navigation;
return (
<Text> Hello World </Text>
);
}
}
const appScreens = StackNavigator({
Home: {screen: App},
})
AppRegistry.registerComponent('IntervalTimer', () => appScreens);
The error is reporting on the const { navigate } = this.props.navigation; declaration. And removing this line does allow the app to deploy but with no header as I would expect.
StackNavigator was installed using NPM and is being imported into the app fine.
There are similar questions posted and I have tried their suggestions. Appreciate any help you can offer!
You can add initialRouteName on StackNavigator's option. Try this.
import React, { Component } from 'react';
import {AppRegistry, Text} from 'react-native';
import {StackNavigator} from 'react-navigation';
class App extends React.Component {
static navigationOptions = {
title: 'Home',
};
render() {
const { navigate } = this.props.navigation;
return (
<Text> Hello World </Text>
);
}
}
export const appScreens = StackNavigator({
Home: { screen: App }
},{
initialRouteName: Home
})
AppRegistry.registerComponent('IntervalTimer', () => appScreens);
If this is just that the prop might have a chance of being undefined, you can just check for undefined.
const { navigate } = this.props.navigation || {};
Assuming at some point the navigation is defined in render, the above should be safe to use. You can try logging it and see if it is always undefined or it gets defined at some point.
console.log(navigate)
The output might be...
undefined
undefined
//defined

goBack always taking to home/first screen in react-navigation

I am working on an app but goback button is not taking me to the back screen.
App.js
import React, { Component } from 'react';
import one from './components/test/one';
import two from './components/test/two';
import three from './components/test/three';
import { DrawerNavigator } from 'react-navigation';
const AppNavigator = DrawerNavigator({
one: {
screen: one,
},
two: {
screen: two,
},
three: {
screen: three,
},
}
);
export default () =>
<AppNavigator />;
components/test/one.js
import React, { Component } from 'react';
import { Button } from 'react-native';
export default class one extends React.Component {
static navigationOptions = {
drawerLabel: 'one',
};
render() {
return (
<Button
onPress={() => this.props.navigation.navigate('two')}
title="Go to Two"
/>
);
}
}
components/test/two.js
import React, { Component } from 'react';
import { Button } from 'react-native';
export default class two extends React.Component {
static navigationOptions = {
drawerLabel: 'two',
};
render() {
return (
<Button
onPress={() => this.props.navigation.navigate('three')}
title="Go to 3"
/>
);
}
}
components/test/three.js
import React, { Component } from 'react';
import { Button } from 'react-native';
export default class three extends React.Component {
static navigationOptions = {
drawerLabel: 'three',
};
render() {
return (
<Button
onPress={() => this.props.navigation.goBack()}
title="Go back to 2"
/>
);
}
}
click on "Go to two" => "Go to 3" => "Go back to 2".
on screen 3, clicking on the "Go back to 2" is always taking me to one.js.
It is not even working if I combine them in one single file.
You are either using the wrong Navigator comp or your requirements are not clear. Basically, You would like to use the StackNavigator for your desired behavior.
The catch is, DrawerNavigator is used to build up a drawer menu. If you swipe from the left you'll see your navigator drawer containing all of your screens, as you can see in the image below.
If you add a button on your screen like below, you'll see your menu open.
<Button title="MENU" onPress={() => this.props.navigation.navigate('DrawerOpen')} />
The conclusion is, whenever we use DrawerNavigator we always go back to initial route, which is whatever we defined as the first item or using the initialRouteName key of the second param of the DrawerNavigator.
It's only the StackNavigator that supports this stacking order you would like to achieve, as the name suggests itself.
What you can do is to wrap a new StackNavigator inside one of the screens of the DrawerNavigator. For example:
const AppNavigator = DrawerNavigator({
drawer1: {
screen: drawer1,
}
});
const drawer1 = StackNavigator({
one: { screen: one },
two: { screen: two },
three: { screen: three },
});