Hi I am implementing react navigation in a react native app, and I am following the docs on react navigation. And I when I run the code this is the result:
My question is how do I make the center content's width same as the screen.
Also, his is my first time using react native expo after switching from reactJS
Code:
navigator code:
import Login from "./Login";
import Signup from "./Signup";
import {
createAppContainer,
NavigationContainer,
NavigationNavigator,
} from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import Chat from "./Chat";
import Error from "./Error";
/**
* This is the screen stack of the navigation stack.
*/
const screens: any = {
default: { screen: Login },
signup: { screen: Signup },
chat: { screen: Chat },
Error: { screen: Error },
};
const stack: NavigationNavigator<any, any> = createStackNavigator(screens);
const container: NavigationContainer = createAppContainer(stack);
export default container;
App.tsx:
import { StatusBar } from "expo-status-bar";
import React from "react";
import { Alert, StyleSheet, Text, View } from "react-native";
import * as expoAppLoading from "expo-app-loading";
import loadFonts from "./assets/fonts/loader";
import Navigator from "./screens/navigator";
/**
* This is the main app component of the Chill&chat application.
*/
const App: React.FC = () => {
const [loading, setLoading] = React.useState(true);
const style: any = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
text: {
fontFamily: "poppinsBold",
},
});
if (loading) {
return (
<expoAppLoading.default
startAsync={async (): Promise<void> => {
await loadFonts();
}}
onFinish={(): void => {
setLoading(false);
}}
onError={(): void => {
Alert.alert("Error", "Error loading fonts");
}}
/>
);
} else {
return (
<View style={style.container}>
<Navigator />
<StatusBar style="auto" />
</View>
);
}
};
export default App;
You should be able to set the width by adding percentage dimensions to your style sheet for the desired element. This may require you do away with flex layout however, or use flex in a parent instead.
container: {
width:'100%',
},
This should solve for the width problem though.
Related
I am trying to make an authentication UI in react native and these are my files:
App.tsx
import React from 'react';
import {
ActivityIndicator,
StyleSheet,
View,
} from 'react-native';
import {
createSwitchNavigator,
createAppContainer,
} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack'
import EmailAccountLoginBlock from '../blocks/email-account-login/src/EmailAccountLoginBlock';
import { getStorageData } from '../framework/src/Utilities';
import AuthenticationStack from './Navigation/AuthStack';
import OtherStack from './Navigation/OtherStack';
class AuthLoadingScreen extends React.Component {
constructor() {
super();
this._bootstrapAsync();
}
// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
const userToken = await getStorageData('authToken');
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
this.props.navigation.navigate(userToken ? 'App' : 'Auth');
};
// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
const AppNavigator =createAppContainer(
createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: OtherStack,
Auth: AuthenticationStack,
},
{
initialRouteName: 'AuthLoading',
},
));
export function App() {
return (
<AppNavigator/>
);
}
AuthStack.tsx
import React, {useState, useEffect} from 'react';
import { createStackNavigator } from 'react-navigation-stack';
import EmailAccountLoginBlock from '../../blocks/email-account-login/src/EmailAccountLoginBlock';
import EmailAccountRegistration from '../../blocks/email-account-registration/src/EmailAccountRegistration';
import ForgotPassword from '../../blocks/forgot-password/src/ForgotPassword';
import VerifyAccount from '../../blocks/user-profile-basic/src/screens/VerifyAccount/VerifyAccountPage';
const AuthStack = createStackNavigator({
EmailAccountLoginBlock: {
screen: EmailAccountLoginBlock,
navigationOptions: {title: 'EmailAccountLoginBlock', header: null},
},
EmailAccountRegistration: {
screen: EmailAccountRegistration,
navigationOptions: {title: 'CustomisableUserProfiles', header: null},
},
ForgotPassword: {
screen: ForgotPassword,
navigationOptions: {title: 'InvestMentExperience', header: null},
},
VerifyAccount: {
screen: VerifyAccount,
navigationOptions: {title: 'CategoryPerference', header: null},
},
});
export default AuthStack;
And OtherStack.tsx is similar to AuthStack.tsk with other screens. I keep getting this error. I think this is an issue with the navigation. I've updated react-navigation, react-navigation-stack but that doesn't seem to help.
I am working on the Expo basic chat app, and I need to use Stack Navigator, which I updated manually to 4.x. When I do that, however, it gives me the error message: (0 , _native.createStackNavigator) is not a function
This is app.js:
import Main from './components/Main';
import Chat from './components/Chat';
// Import React Navigation
import { createStackNavigator } from '#react-navigation/native'
// Create the navigator
const navigator = createStackNavigator({
Main: { screen: Main },
Chat: { screen: Chat },
});
// Export it as the root component
export default navigator
Here is main.js:
import React, { Component } from 'react';
import {
StyleSheet,
TextInput, // 1. <- Add this
View,
} from 'react-native';
class Main extends React.Component {
state = { name: '' } // 2. <- Add the component state
render() {
return (
<View>
<TextInput
style={styles.nameInput}
placeHolder="John Cena"
value={this.state.name}
/>
</View>
);
}
}
const offset = 24;
const styles = StyleSheet.create({
nameInput: { // 3. <- Add a style for the input
height: offset * 2,
margin: offset,
paddingHorizontal: offset,
borderColor: '#111111',
borderWidth: 1,
},
});
Any possible solutions?
Update to react navigation 5.x, the import { createStackNavigator } from '#react-navigation/native' is a syntax for 5.x, you are using 4.x
I am trying different ways to display a conditional button based on the athtentication state, but i keep getting into trouble. I have an app.js that defines the stacknavigator, which adds a button to the header giving the option to log out if authenticated.
I wrote a handleLogout function that should perform this.
import React from 'react';
import { Button, Image, View, Text } from 'react-native';
import firebase from 'react-native-firebase';
import Loading from './Loading';
import SignUp from './SignUp';
import Login from './Login';
import Main from './Main';
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import { useNavigation } from '#react-navigation/native';
// eslint-disable-next-line no-undef
handleLogOut = () => {
const navigation = useNavigation();
firebase
.auth()
.signOut()
.then(() => this.props.navigation.navigate('Login'))
.catch(error => this.setState({errorMessage: error.message}));
};
const AppNavigator = createStackNavigator(
{
Loading: Loading,
SignUp: SignUp,
Login: Login,
Main: Main,
},
{
initialRouteName: 'Loading',
defaultNavigationOptions: {
headerLeft: null,
headerRight: () => {
let button = this.loggedIn? (
<Button
onPress={this.handleLogOut}
title="Log-out"
color="#fff"
/>
)
:
(
<Button
onPress={() => alert('Please log in')}
title="Log-in"
color="#fff"
/>
)
return button;
},
headerStyle: {
backgroundColor: '#c6f1e7',
},
headerTintColor: '#59616e',
headerTitleStyle: {
fontFamily: 'Raleway-Regular',
fontWeight: '400',
},
},
},
);
export default createAppContainer(AppNavigator);
App.js calls on loading.js where the value for loggedin is declared, based on the authentciation state and then loads either main.js or sign-up. in this case the main page is loaded, which means that someone is authenticated:
// Loading.js
import React from 'react';
import {View, ActivityIndicator, StyleSheet} from 'react-native';
import firebase from 'react-native-firebase';
export default class Loading extends React.Component {
componentDidMount() {
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.setState({ loggedIn: true })
this.props.navigation.navigate(user ? 'Main' : 'SignUp');
} else {
this.setState({ loggedIn: false })
}
});
}
render() {
return (
<View style={styles.container}>
<ActivityIndicator size="large" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#c6f1e7',
},
});
Now the page redirects to main and shows the welcome message, which indicates that the user is logged in, but the button in the header is saying 'log-in' as well, which means the button is not chosen well. I assume that this is because the loggedin value is not read and it automatically sets it on loggedin: false.
Here is the code for main.js
// Main.js
import React from 'react';
import { View, Text, StyleSheet, Button } from 'react-native';
import firebase from 'react-native-firebase';
import { createAppContainer } from 'react-navigation';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import Kowops from './Kowops';
import Scan from './Scan';
import Wallet from './Wallet';
export class Main extends React.Component {
state = { currentUser: null }
componentDidMount() {
const { currentUser } = firebase.auth()
this.setState({ currentUser })
}
render() {
const { currentUser } = this.state
return (
<View style={styles.container}>
<Text>
Hidiho {currentUser && currentUser.email}!
</Text>
</View>
)
}
}
const bottomTabNavigator = createBottomTabNavigator(
{
Main: {screen: Main},
Kowops: {screen:Kowops},
Scan: {screen:Scan},
Wallet: {screen:Wallet},
},
{
//initialRouteName: 'Main',
tabBarOptions: {
initialRouteName: 'Main',
activeTintColor: '#59616e',
inactiveTintColor: '#a9a9a9',
style: {
backgroundColor: '#c6f1e7',
}
},
});
export default createAppContainer(bottomTabNavigator);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
})
So I need to figure out how to ensure that the value of isloggedin is read properly and the script loads the right button.
Does anyone have a clue?
Thanks in advance!!
Tim
The key here is that you can't use state across different components without passing them as props or through navigation params in this case. You can't use the useNavigation hook outside of a functional component so you should pass the navigation object around when you need it outside of a component (handleLogout is not a component).
Here are some alterations I would make, however I would suggest that you will need to make further changes based on the idea that you can use navigation params to pass information between screens. See more here https://reactnavigation.org/docs/en/params.html.
App.js
DefaultNavigationOptions can be a function which has a navigation prop, this is the navigation object you can use to get params or navigate in the context of the router.
remove that eslint exception because you don't need it, just properly declare the variable. Remove the "this" from you handleLogout function call because it is not a class attribute. Use navigation.getParam to get the isLoggedIn variable which you can pass in the navigate function call.
const handleLogout = navigation => {
firebase
.auth()
.signOut()
.then(() => navigation.navigate('Login'))
.catch(error => this.setState({errorMessage: error.message}));
}
...
defaultNavigationOptions: ({navigation}) => ({
headerRight: () => {
const isLoggedIn = navigation.getParam('isLoggedIn', false);
let button = isLoggedIn ? (
<Button
onPress={() => handleLogOut(navigation)}
title="Log-out"
color="#fff"
/>
) : ...
} ...
Now Loading.js
Here you need to add a navigation param to your navigate call which can then be used in the header
...
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.props.navigation.navigate('Main', {isLoggedIn: true});
} else {
this.props.navigation.navigate('SignUp', {isLoggedIn: false});
}
});
here is a modified version of your code in snack that you can see will get the logged in param and show the logout button https://snack.expo.io/#dannyhw/intrigued-graham-crackers
You will need to make further changes to fix other functionality because I only changed the minimum to show that you can use the navigation param.
I'm trying to nest a bottomTabNavigator inside the DrawerNavigator using the React Navigation library but an error comes up telling me to use a React component or a Navigator to for the DrawerNavigator's route.
This is the DrawerNavigator.js file where i create the DrawerNavigator.
import React, { Component } from 'react';
import {createDrawerNavigator} from 'react-navigation';
import SideBar from '../components/SideBar';
import MainTabNavigator from './MainTabNavigator';
export default createDrawerNavigator({
Home: {
screen: MainTabNavigator,
}
},{
contentComponent: SideBar
})
This is the MainTabNavigator.js file where i create the bottomTabBarNavigator
const MainTabNavigator = createBottomTabNavigator({
Home: HomeStack,
MultiBar: {
screen: () => null,
navigationOptions: ({navigation}) => ({
tabBarIcon: () => (
<CustomTabBarBottom />
)
}),
params: {
navigationDisabled: true
}
},
Video: VideoStack
}, {
tabBarComponent: props =>
<TabBarComponent
{...props}
/>,
tabBarOptions: {
showLabel: false,
},
});
export default MainTabNavigator;
Please look into this and tell me if i'm missing something, thanks in advance!
This is my code of bottomTabBar with Drawer. may this will help you.
Just add your MainTabNavigation as the first screen of your createDrawerNavigator in your code.
I have used react-navigation version 3.0
import React, { Component } from "react";
import { View, Text } from "react-native";
import {
createAppContainer,
createDrawerNavigator,
createStackNavigator
} from "react-navigation";
import Heal from "./component/tabs/Heal";
import Submit from "./component/tabs/Submit";
import { createBottomTabNavigator, BottomTabBar } from "react-navigation-tabs";
import ProfileSetting from "./component/drawerTabs/ProfileSetting";
import ChangePassword from "./component/drawerTabs/ChangePassword";
import Help from "./component/drawerTabs/Help";
import Logout from "./component/drawerTabs/Logout";
import Drawer from "./component/drawerTabs/Drawer";
import { FontTypes } from "./style/Font";
import { ColorCodes } from "./style/Color";
const TabBarComponent = props => <BottomTabBar {...props} />;
export const TabScreens = createBottomTabNavigator(
{
"Heal a case": { screen: Heal },
"Submit a case": { screen: Submit }
},
{
tabBarComponent: props => (
// <BottomTabView {...props}/>
<TabBarComponent
{...props}
activeBackgroundColor={ColorCodes.primary}
showIcon={false}
allowFontScaling={true}
activeTintColor="#fff"
inactiveTintColor="#000"
labelStyle={{ fontSize: 17, fontFamily: FontTypes.Roboto }}
tabStyle={{
justifyContent: "center",
borderWidth: 0
}}
style={
{
// backgroundColor: "red"
}
}
/>
)
}
);
export const MyDrawerNavigator = createDrawerNavigator(
{
"My Cases": {
screen: TabScreens
},
"Profile Setting": {
screen: ProfileSetting
},
"Change Password": {
screen: ChangePassword
},
Help: {
screen: Help
},
Logout: {
screen: Logout
}
},
{
contentComponent: Drawer,
drawerBackgroundColor: "white",
drawerType: "front",
contentOptions: {
labelStyle: {
fontFamily: FontTypes.Roboto,
color: ColorCodes.primary,
},
activeLabelStyle:{
color:ColorCodes.iconColor
}
}
}
);
export default createAppContainer(MyDrawerNavigator);
This is my AppNavigator.js which is used as the main app container:
import React from 'react';
import { createSwitchNavigator, createAppContainer } from 'react-navigation';
import AuthLoadingScreen from '../screens/AuthLoadingScreen';
import MainTabNavigator from './MainTabNavigator'
import AuthStackNavigator from './AuthStackNavigator';
import DrawerNavigator from './DrawerNavigator';
const MainAppNavigator = createSwitchNavigator({
AuthLoadingScreen: AuthLoadingScreen,
App: DrawerNavigator,
Auth: AuthStackNavigator,
});
const AppNavigator = createAppContainer(MainAppNavigator)
export default AppNavigator
By removing the MainTabNavigator import which i don't use at all in the file, the error goes away (which is really bizarre ).
Not sure if this still helps but I had the same problem and solved it by having all components in one file and moving the other navigators up, so that the createDrawerNavigator component is at the bottom of the file.
This looks like hoisting does not work here? I am actually confused about this, but there you go.
My application contain drawer navigator and stack navigator. But issue is that when i tried to goback it takes me to first screen even if i am 2-3 stack deep. It don't show previous screen it always takes me to main screen. Below is my App.js code
import React from 'react';
import {
ActivityIndicator,
AsyncStorage,
Button,
StatusBar,
StyleSheet,
View,
} from 'react-native';
import {StackNavigator, SwitchNavigator, DrawerNavigator} from 'react-navigation';
import Screen1 from './Screen/Screen1';
import Screen2 from './Screen/Screen2';
import Screen3 from './Screen/Screen3';
import Screen4 from './Screen/Screen4';
import Screen5 from './Screen/Screen5';
import ScreenList from './Screen/ScreenList';
import Login from './Screen/Login';
class AuthLoadingScreen extends React.Component {
constructor() {
super();
this._bootstrapAsync();
}
// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
const userToken = await AsyncStorage.getItem('user');
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
this.props.navigation.navigate(userToken ? 'App' : 'Auth');
};
// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator/>
<StatusBar barStyle="default"/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
const AppStack = DrawerNavigator({
Screen1: { screen: Screen1},
Screen2: { screen: Screen2},
Screen3: { screen: Screen3},
Screen4: { screen: Screen4},
Screen5: { screen: Screen5},
ScreenList: { screen: ScreenList},
}, {contentComponent: SideBar});
const AuthStack = StackNavigator({Login: { screen: Login}},{headerMode:'none'});
const MyNavigator = SwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading'
}
);
export default class App extends React.Component {
render() {
return <MyNavigator />;
}
}
From Screen 1, i click on button and go to screen 2 and screen 3 like:
onPress={() => navigate('Screen2', { })}
And it works fine, but when i go back using bellow code from screen 3 it takes me to screen 1 not screen 2
this.props.navigation.goBack();
Am i missing something?
Did you try
1 -> 2 -> 3 -> 4
<Button
onPress={() => goBack('3')}
title="Go to 3 screen"
/>