React Native's Navigator is not working - reactjs

Navigator is not working, it's empty.I'm getting a blank page, Home component is not showing up. I tried other components and got the same result.
Addding this so I can post the question
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
import React, { Component } from 'react';
import {
AppRegistry,
View,
Text,
StyleSheet,
Navigator
} from 'react-native';
import Login from './components/Login';
import Home from './components/Home';
import LoginForm from './components/LoginForm';
export default class App extends Component {
renderScene(route, navigator) {
console.log(route);
if(route.name == 'login') {
return <Login navigator={navigator} />
}
if(route.name == 'home') {
return <Home navigator={navigator} />
}
}
render() {
return (
<View style={styles.container}>
<Navigator
initialRoute={{name: 'home'}}
renderScene={this.renderScene.bind(this)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#4fb0c9',
}
});

I haven't tested your code but I can see you didn't use renderScene() in the right way. What I suggest is to move your routes out of App.js file and create a routes.js in this way so you are avoiding to have lots of if for your routes:
Route.js
import LoginView from './LoginView';
import HomeView from './HomeView';
let routes = {
HomeView: {
name: 'HomeView',
component: HomeView,
index: 0
},
LoginView: {
name: 'LoginView',
component: LoginView,
index: 1,
sceneConfig: Navigator.SceneConfigs.PushFromRight //you can change your view transitions here
},
};
export default Routes;
And in your app.js file you have to
import Routes from './routes';
And update render()
render(){
<Navigator
initialRoute={Routes.HomeView}
sceneStyle={styles.container}
renderScene={(route, navigator) => {
const Component = route.component;
return <Component
navigator={navigator} //pass it down to each view so it can be called
route={route}
/>
}}
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FadeAndroid;
}}
/>
}
Hope it helps you out.

Sample code for navigator
import SplashScreen from './SplashScreen';
class AppContainer extends Component {
render() {
return (
<Navigator
initialRoute={{ id: 'SplashScreen', name: 'Index' }}
renderScene={this.renderScene.bind(this)}
configureScene={(route, routeStack) => Navigator.SceneConfigs.FloatFromRight}
/>
);
}
renderScene = (route, navigator) => {
if (route.id === 'SplashScreen') {
return (
<SplashScreen
navigator={navigator}
/>
);
}
}
}
We get navigator as props in components when we are passing navigator in splashScreen.

Related

Can’t find variable navigation in react native expo

Before I begin, I'd like to say that there were other questions that were answered that had a similar problem but none of those solutions worked for me. I just started using React Native Expo today and I'm finding the navigation part a little difficult. Take a look at the code:
App.js
import React, { Component } from 'react';
import HomePage from './HomePage'
import DetailsPage from './DetailsPage'
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="HomePage" component={HomePage} />
<Stack.Screen name="DetailsPage" component={DetailsPage} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
I've got 2 .js files that represent 2 pages of my app, here's the code for those files:
HomePage.js
import React, { useState } from 'react';
import { StyleSheet, Text, View, SafeAreaView, FlatList, TouchableOpacity } from 'react-native';
export default function HomePage() {
// Create a temporary list to populate the table view
const [orders, setOrders] = useState([
{ company: 'Airbnb', date: '20/02/2020', author: 'Mohammed Ajmal', itemOrdered: 'Sack Craft paper', id: '1' },
{ company: 'Apple', date: '15/01/2020', author: 'Ilma Ajmal', itemOrdered: 'Multiwall paper sacks', id: '2' },
{ company: 'Google', date: '30/12/2019', author: 'Rifka Ajmal', itemOrdered: 'Rigid paper sacks', id: '3' },
{ company: 'Facebook', date: '29/06/2020', author: 'Fahim Khalideen', itemOrdered: 'Paper bags', id: '4' },
])
return (
<View style={styles.container}>
<SafeAreaView>
{/* Create the table view */}
<FlatList
style = {styles.tableView}
data = {orders}
keyExtractor = {(item) => item.id}
renderItem = {({ item }) => (
<TouchableOpacity style = {styles.tableViewItem} onPress = {() => {
navigation.navigate('DetailsPage')
}}>
<Text style = {styles.companyName}>{ item.company }</Text>
<Text style = {styles.date}>{ item.date } | { item.author }</Text>
<Text style = {styles.itemOrdered}>{ item.itemOrdered }</Text>
</TouchableOpacity>
)}
/>
</SafeAreaView>
</View>
);
}
// Stylesheet
DetailsPage.js
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function DetailsPage() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
What I'm trying to create is a table view, when clicked, it should take the user to the Details page, but I'm getting an error saying
Can't find variable: navigation
I tried almost everything I could find in Stack Overflow but nothing helped me, maybe because the code in those answers were different and I couldn't understand how to make it work for mine.
You are not having a parameter for the navigation change the
line
export default function HomePage() {
to
export default function HomePage({navigation}) {
And it will work.
Or you could make use of the withNavigation when using a class component.
import { withNavigation } from 'react-navigation';
class DetailsPage extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
}
export default withNavigation(DetailsPage);

How to navigate other screen by declaring another class inside of the first class using react navigation

I'm currently new here on this react native, I got confuse regarding switching my screen to another screen, I don't know why my import second screen not working when i click the onpress function declared to my first screen.,
import SecondScreen from './Screens/SecondScreen';
export default class FirstScreen extends Component<Props> {
render() {
return (
<View style={styles.container}>
<Header searchBar rounded>
<Left>
<Button transparent>
<Icon name='menu'/>
</Button>
</Left>
<Body>
<Title>Pay Bills</Title>
</Body>
<Item>
<Icon name="ios-search" />
<Input placeholder="Search" />
<Icon name="ios-people" />
</Item>
<Button transparent>
<Text>Search</Text>
</Button>
</Header>
<StatusBar backgroundColor='#6633ff' barStyle='light-content' />
<Text>How much would you like to pay?</Text>
<View style={{flex:1}}>
<Image onPress={()=> this.props.navigation.navigate('SecondScreen')} source={require('./Assets/example.png')}
style={{flex:1,width:null,height:null,resizeMode:'cover'}}
/>
</View>
</View>
);
}
}
As you can see I use the onpress function to navigate second screen.
onPress={()=> this.props.navigation.navigate('SecondScreen')}
My app.js file
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* #format
* #flow
*/
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, SafeAreaView, ScrollView, Dimensions} from 'react-native';
import {createDrawerNavigator, DrawerItems} from 'react-navigation';
//screens
import LoginScreen from './Screens/LoginScreen';
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
android:
'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
type Props = {};
export default class App extends Component<Props> {
render() {
return (
<AppDrawerNavigator/>
);
}
}
const AppDrawerNavigator = createDrawerNavigator({
Login:LoginScreen,
});
How to move my first screen to the second screen using react navigation.
thanks.
pass the route of second screen also in react navigation
then you can navigate to second screen
You need to make some change in app.js. add createDrawerNavigator inside createStackNavigator. Add those screen into stacknavigator in which you do not want to add into drawer. In createDrawerNavigator add those screens in which you want to show in drawer.
Please check following code
import React, { Component } from "react";
import {
Platform,
StyleSheet,
Text,
View,
SafeAreaView,
ScrollView,
Dimensions
} from "react-native";
import { createStackNavigator,createDrawerNavigator DrawerItems } from "react-navigation";
//screens
import LoginScreen from "./Screens/LoginScreen";
const instructions = Platform.select({
ios: "Press Cmd+R to reload,\n" + "Cmd+D or shake for dev menu",
android:
"Double tap R on your keyboard to reload,\n" +
"Shake or press menu button for dev menu"
});
type Props = {};
export default class App extends Component<Props> {
render() {
return( <StackNav />);
}
}
const StackNav = createStackNavigator(
{
Drawer: {
screen:AppDrawerNavigator ,
navigationOptions: {
headerMode: "none",
header: null
}
},
First: {
screen: First,
navigationOptions: {
headerMode: "none",
header: null
}
},
Second: {
screen: Second,
navigationOptions: {
headerMode: "none",
header: null
}
}
},
{
initialRouteName: "Drawer"
}
);
const AppDrawerNavigator = createDrawerNavigator({
Login: { screen: LoginScreen },
})

React-Native the child component don't render the information within the parent component

I'm developing a React Native app that using a ScrollView. I want to display an amount of items (A card with title and a child component).
The problem comes when I have to render each item, while the parent renders ok, the child does not.
I don't know where could be the issue, here's my code:
import React, {Component} from 'react';
import {View, Text} from 'react-native';
const mismo =[
'Mismo',
'Mismo',
'Mismo',
'Mismo',
'Mismo'
];
class Mismo extends Component {
renderMismo2(){
mismo.map((item) =>{
return(
<View>
<Text>{item}</Text>
</View>
)
})
}
render(){
return(
<View>
{this.renderMismo2()}
</View>
);
}
}
export default Mismo;
=================================
import React, {Component} from 'react';
import {View, Text, ScrollView} from 'react-native';
import {Card} from 'react-native-elements';
import PriceCard from '../components/PriceCard';
import Mismo from '../components/Mismo';
class OrderPricingCard extends Component{
renderAllPrices(){
this.props.data.orders.map((item, i) => {
return(
<View>
<PriceCard
key={item.transporterName}
data={item}
/>
</View>
);
})
}
renderMismo(){
return(
<Mismo />
);
}
render () {
return (
<Card
containerStyle={styles.cardContainer}
title={`Pedido: ${this.props.data.id}`}
>
<ScrollView
horizontal
>
{this.renderMismo()}
{this.renderAllPrices()}
</ScrollView>
</Card>
);
}
}
const styles = {
cardContainer:{
borderRadius: 10,
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
}
}
export default OrderPricingCard;
This can be an easy mistake to make! I've done it several times. What's happened is you've forgotten the return statement for the render methods (renderMismo2() and renderAllPrices()) found in each component. Although the map methods correctly have return statements, you're not actually returning anything from the functions themselves.
If you were to console.log() either of those function calls above the return in the React render() method, you would see undefined in the console.
Here's what they would look like corrected.
renderAllPrices(){
// added the 'return' keyword to begin the line below
return this.props.data.orders.map((item, i) => {
return(
<View>
<PriceCard
key={item.transporterName}
data={item}
/>
</View>
);
})
}
renderMismo2(){
// same here, added the 'return' keyword
return mismo.map((item) =>{
return(
<View>
<Text>{item}</Text>
</View>
)
})
}
I tested the above in a React Native sandbox and it works. Hope that helps!

react-native, how to factorize code over many tabs

I use react-native to create ios and android app
I create a test app with TabNavigator working good plus a sidemenu ( the button to open it should be in the top action bar ) and floatings actions buttons (the red circle labeled FAB on the picture). All this code is new defined on first tab : app.js.
Each tab have it's own js file with code and render.
My question is :
How to get this sidemenu,action bar and floating buttons on ALL tabs without coping all the render code and js functions over all the other tabs Js files.
when i click on a tab only the green part will change
my App.js
import React, { Component } from "react";
import {...} from "react-native";
import { TabNavigator } from "react-navigation";
import Imagetest from "./Photo";
import ListFlatlist from "./ListFlatlist";
... // importing the other file for the tabs
import styles from "./css/styles";
import SideMenu from "react-native-side-menu";
import Menu from "./Menu";
class App extends Component {
constructor(props) { ... }
...
render() {
const menu = <Menu onItemSelected={this.onMenuItemSelected} />;
return (
<SideMenu
menu={menu}
isOpen={this.state.isOpen}
onChange={isOpen => this.updateMenuState(isOpen)}
>
<View style={styles.container}>
{/* my app.js content
*/}
// this is floating buttons
<ActionButton buttonColor="rgba(231,76,60,1)">
<ActionButton.Item buttonColor='#9b59b6' title="New Task" onPress={() => console.log("notes tapped!")}>
<Icon name="md-create" style={styles.actionButtonIcon} />
</ActionButton.Item>
</ActionButton>
</View>
</SideMenu>
);
}
}
const AppNavigator = TabNavigator(
{
H: { screen: App },
f: { screen: ListFlatlist },
Img: { screen: Imagetest },
B: { screen: Buttonpage },
S: { screen: ListSectionlist },
F: { screen: Fetchpage }
}
);
export default AppNavigator;
If a create new components for sidemenu, action bar and FAB I have to put them on all the tab render, not the cleanest way for me but i don't see other solution now.
I put an example repo together on Github. Thats actually all it needs:
// #flow
import React, { Component } from "react";
import { View } from "react-native";
import { StackNavigator, TabNavigator } from "react-navigation";
import ActionButton from "react-native-action-button";
import Profile from "./Profile";
import Tab1View from "./Tab1";
import Tab2View from "./Tab2";
import Tab3View from "./Tab3";
const TabView = TabNavigator({
tab1: { screen: Tab1View },
tab2: { screen: Tab2View },
tab3: { screen: Tab3View },
})
const Home = (props) => {
return (
<View style={{flex: 1}}>
<TabView navigation={props.navigation} />
<ActionButton offsetY={100} />
</View>
);
}
Home.router = TabView.router;
const StackView = StackNavigator({
home: { screen: Home },
profile: { screen: Profile },
});
export default class App extends Component {
render() {
return (
<View style={{ flex: 1 }}>
<StackView />
</View>
);
}
}

Passing props in react-native-flux-router

So I'm still a bit new to React Native, but I've got an app working nearly how I want it to. I have App.js which uses the TabBarIOS component to display my tabbed navigation at the bottom of the screen. When you touch a tab, the state updates and the relevant content is loaded and displayed:
App.js
import React, { Component } from 'react';
import { TabBarIOS, Platform, Image } from 'react-native';
import IconII from 'react-native-vector-icons/Ionicons';
import IconMCI from 'react-native-vector-icons/MaterialCommunityIcons';
import Colors from './Colors';
import RouterItem1 from './routers/RouterItem1';
import RouterItem2 from './routers/RouterItem2';
import RouterHome from './routers/RouterHome';
import Settings from './components/Settings';
class FooterNav extends Component {
state = {
selectedTab: 'home',
};
handleClick = (routeData) => {
console.log('This has received data', routeData);
this.setState({ selectedTab: routeData });
console.log(this.state);
}
renderCurrentView() {
switch (this.state.selectedTab) {
case 'home':
return (
<RouterHome handleClick={this.handleClick} />
);
case 'item2':
return (
<RouterItem2 />
);
case 'item1':
return (
<RouterItem1 />
);
case 'settings':
return (
<Settings />
);
default:
return false;
}
}
render() {
return (
<TabBarIOS
unselectedTintColor={Colors.third} //Unselected labels
unselectedItemTintColor={Colors.third} //Unselected icons
tintColor={Colors.brandPrimary} //Selected
barTintColor={Colors.light} //Bar background
>
<IconII.TabBarItem
title="Home"
iconName="ios-home-outline"
selectedIconName="ios-home"
selected={this.state.selectedTab === 'home'}
receiveData={this.receiveData}
onPress={() => {
this.setState({
selectedTab: 'home',
});
}}
>
{this.renderCurrentView()}
</IconII.TabBarItem>
<TabBarIOS.Item
icon={require('./images/item2-icon-line#3x.png')}
selectedIcon={require('./images/item2-icon-selected#3x.png')}
title="item2"
selected={this.state.selectedTab === 'item2'}
onPress={() => {
this.setState({
selectedTab: 'item2',
});
}}
>
{this.renderCurrentView()}
</TabBarIOS.Item>
<IconMCI.TabBarItem
title="item1"
iconName="cookie"
selectedIconName="cookie"
selected={this.state.selectedTab === 'item1'}
onPress={() => {
this.setState({
selectedTab: 'item1',
});
}}
>
{this.renderCurrentView()}
</IconMCI.TabBarItem>
<IconII.TabBarItem
title="More"
iconName="ios-more-outline"
selectedIconName="ios-more"
selected={this.state.selectedTab === 'settings'}
onPress={() => {
this.setState({
selectedTab: 'settings',
});
}}
>
{this.renderCurrentView()}
</IconII.TabBarItem>
</TabBarIOS>
);
}
}
module.exports = FooterNav;
react-native-router-flux is a great plugin, once it pulls in a router the flow is exactly what I want it to be. The only problem I have is with the <RouterHome> module:
RouterHome.js
import React from 'react';
import { Scene, Router } from 'react-native-router-flux';
import styles from '../Styles';
import { content } from '../content.js';
import AnotherScene from '../components/pages/AnotherScene';
import Home from '../components/Home';
const RouterHomeComponent = () => {
return (
<Router
sceneStyle={styles.sceneStyle}
navigationBarStyle={styles.navBar}
titleStyle={styles.navBarTitle}
barButtonIconStyle={styles.barButtonIconStyle}
>
<Scene
key="Home"
component={Home}
title={content.heading}
hideNavBar
/>
<Scene
key="AnotherScene"
component={AnotherScene}
title='title'
hideNavBar={false}
/>
</Router>
);
};
export default RouterHomeComponent;
The default view that is loaded is the <Home> module:
Home.js
import React, { Component } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { Actions } from 'react-native-router-flux';
import styles from '../Styles';
import { content } from '../content.js';
class Home extends Component {
displayItem1 = () => {
this.props.handleClick('item1');
}
displayItem2 = () => {
this.props.handleClick('item2');
}
displayAnotherScene() {
Actions.AnotherScene();
}
render() {
return (
<View style={styles.viewWrapperHome}>
<Text style={styles.heading}>{content.greeting}</Text>
<TouchableOpacity onPress={this.displayItem1}>
<Text>First item</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.displayItem2}>
<Text>Second item</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.displayAnotherScene}>
<Text>Another scene</Text>
</TouchableOpacity>
</View>
);
}
}
export default Home;
So what I expect to happen is that if the user clicks on the first two buttons displayed on the screen (First item/Second item), the prop will be passed back to App.js, the state will change and the scene will be updated. It basically is an alternative way of navigating without using the footer menu.
I know that this would work without using the react-native-router-flux module as I had it running before I added it in. The problem is that I really need it to handle the other pages from the <Home> module (many more to add).
Can anyone suggest a way I can pass back the props through the router back to my App.js?
Okay, so I actually figured this out - it turned out to totally be my fault; the props weren't getting passed to RouterHome and so they got lost either side. The new RouterHome looks like this:
RouterHome.js
import React from 'react';
import { Scene, Router } from 'react-native-router-flux';
import styles from '../Styles';
import { content } from '../content.js';
import AnotherScene from '../components/pages/AnotherScene';
import Home from '../components/Home';
const RouterHomeComponent = (props) => { <---Didn't add props
return (
<Router
sceneStyle={styles.sceneStyle}
navigationBarStyle={styles.navBar}
titleStyle={styles.navBarTitle}
barButtonIconStyle={styles.barButtonIconStyle}
>
<Scene
key="Home"
component={Home}
title={content.heading}
hideNavBar
handleClick={props.handleClick} <---Didn't pass props
/>
<Scene
key="AnotherScene"
component={AnotherScene}
title='title'
hideNavBar={false}
/>
</Router>
);
};
export default RouterHomeComponent;
I've marked the two changes I made. Hopefully this will help someone! :)

Resources