I am using react-navigation for routing between screens. Now, the scenario is I have used SwitchNavigator for authentication.
Example:
SplashScreen
this.props.navigation.navigate(userToken? 'App' : 'Auth', { extraParams: value});
LoginScreen / Home Screen
this.props.navigation.state.params.extraParams
This returns only routeName and key. Please find the reference code that I am using.
import React from 'react';
import {
ActivityIndicator,
AsyncStorage,
Button,
StatusBar,
StyleSheet,
View,
} from 'react-native';
import { createStackNavigator, createSwitchNavigator, createAppContainer } from 'react-navigation';
class SignInScreen extends React.Component {
static navigationOptions = {
title: 'Please sign in',
};
render() {
return (
<View style={styles.container}>
<Button title="Sign in!" onPress={this._signInAsync} />
</View>
);
}
_signInAsync = async () => {
await AsyncStorage.setItem('userToken', 'abc');
this.props.navigation.navigate('App');
};
}
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome to the app!',
};
render() {
return (
<View style={styles.container}>
<Button title="Show me more of the app" onPress={this._showMoreApp} />
<Button title="Actually, sign me out :)" onPress={this._signOutAsync} />
</View>
);
}
_showMoreApp = () => {
this.props.navigation.navigate('Other');
};
_signOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
}
class OtherScreen extends React.Component {
static navigationOptions = {
title: 'Lots of features here',
};
render() {
return (
<View style={styles.container}>
<Button title="I'm done, sign me out" onPress={this._signOutAsync} />
<StatusBar barStyle="default" />
</View>
);
}
_signOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
}
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('userToken');
// 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 = createStackNavigator({ Home: HomeScreen, Other: OtherScreen });
const AuthStack = createStackNavigator({ SignIn: SignInScreen });
export default createAppContainer(createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
));
Can anyone please help to get an appropriate solution to pass extra params from SplashScreen to HomeScreen or LoginScreen?
Related
fairly new to React Native. I have read the stack navigator docs and still don't get how to do this.
So I have a bottom tab navigator, and I want to implement a stack navigator in one of the tabs, so I can navigate from the main tab screen to the second screen, but from the second screen to third screen I cannot navigate as it can't find the variable "navigation", which is understandable because I'm using different js files for each screen. How do I pass over the navigation variable to the other screen? Below is my code:
OrderScreen.js:
imports...
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
const styles = StyleSheet.create({
...
}
});
function Orderscreen({ navigation }) {
return (
<View style={styles.welcome}>
<View styles={styles.container}>
<Button style={styles.button1} color="warning" uppercase onPress={() => { navigation.navigate('Scan QR code') }}><Text style={styles.buttonText}>Take me to screen SCAN QR CODE</Text></Button>
</View>
</View>
)
};
import { Qrcodescanner } from './qrcodescanner';
import { Menu } from './menu';
import { render } from 'react-dom';
function MenuScreen({ navigation }) {
return(
<Menu></Menu>
)
}
function QRScanScreen({ navigation }) {
return(
<Qrcodescanner></Qrcodescanner>
)
}
export default function App() {
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={Orderscreen} />
<Stack.Screen name="Scan QR code" component={QRScanScreen}
options={{
headerRight: () => (
<Button shadowless
onlyIcon icon="question" iconFamily="antdesign" iconSize={30} color="info" iconColor="#fff" style={{ width: 35, height: 35, marginRight: 20 }}
/>
),
}}
/>
<Stack.Screen name="Menu" component={MenuScreen} />
</Stack.Navigator>
);
}
Qrcodescanner.js:
export class Qrcodescanner extends React.Component {
...
render() {
const { hasCameraPermission, scanned } = this.state;
if (hasCameraPermission === null) {
return <Text> Requesting for camera permission </Text>;
}
if (hasCameraPermission === false) {
return <Text> No access to camera </Text>;
}
return (
<View
style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
}}> ...
</View>
);
}
handleBarCodeScanned = ({ type, data}) => {
this.setState({
scanned: true,
});
alert(`Bar code with type ${type} and data ${data} has been scanned!`);
navigation.navigate('Menu')
};
};
So when I do scan something, it should navigate to the 'Menu' screen but instead I get the error: 'can't find variable: navigation'. How do I pass the navigation variable to a different js file?
i have seen your cod and got a solution for you you just have to create a new file NavigationServices.js
import { NavigationActions } from "react-navigation";
let _navigator;
function setTopLevelNavigator(navigatorRef) {
_navigator = navigatorRef;
}
function navigate(routeName, params) {
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params
})
);
}
// add other navigation functions that you need and export them
export default {
navigate,
setTopLevelNavigator
};
and then import the file in your .js file and use it to navigate like in your OrderScreen.js:
import NavigationService from "../NavigationService";
and use it like this.
NavigationService.navigate("Qrcodescanner");
I am trying to navigate between the screens. I installed npm react-navigation for this purpose. I am trying to go back from my AutoCompActivity page to app.js page. I have the following code on my AutoCompActivity page:
import HomeActivity from '../App'
class AutocompActivity extends Component {
constructor(props) {
super(props);
this.state = {
// Default Value of this State.
Loading_Activity_Indicator: true,
text:'',
selected_topic_id: -1,
}
this.arrayholder=[];
}
OpenHomePageFunction = () =>
{
this.props.navigation.navigate('Home');
}
and finally, I have this in my code:
export default MyNewProject= StackNavigator(
{
Home: {screen:HomeActivity}
}
I am getting the below error:
My AutoCompActivity.js resides inside a folder called Module, module reside inside the root folder' and app.js resides into the root folder of application.
Below is my App.js code:
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View, Button, Image, TouchableOpacity,Platform } from 'react-native';
import { StackNavigator } from 'react-navigation';
import MissionActivity from './Modules/MissionActivity' ;
import AutoCompActivity from './Modules/AutoCompActivity' ;
import SearchServices from './Modules/SearchServices';
class MainActivity extends Component {
constructor(){
super();
this.state={
isVisible : true,
}
}
Hide_Splash_Screen=()=>{
this.setState({
isVisible : false
});
}
componentDidMount(){
var that = this;
setTimeout(function(){
that.Hide_Splash_Screen();
}, 5000);
}
static navigationOptions = {
title: '',
};
OpenSecondActivityFunction = () =>
{
this.props.navigation.navigate('Mission');
}
OpenThirdActivityFunction = () =>
{
this.props.navigation.navigate('autoComp');
}
OpenSearchSer = () =>
{
this.props.navigation.navigate('SearchSer');
}
render()
{
let Splash_Screen = (
<View style={styles.SplashScreen_RootView}>
<View style={styles.SplashScreen_ChildView}>
{/* Put all your components Image and Text here inside Child view which you want to show in Splash Screen. */}
<Image source={require('./Resources/CAC.png')}
style={{width:'100%', height: '100%', resizeMode: 'contain'}} />
</View>
<TouchableOpacity
activeOpacity = { 0.5 }
style={styles.TouchableOpacity_Style}
onPress={this.Hide_Splash_Screen} >
<Image source={{uri: 'https://reactnativecode.com/wp-content/uploads/2018/01/close_button.png'}}
style={{width:25, height: 25}} />
</TouchableOpacity>
</View> )
return(
<View style = { styles.MainContainer }>
<View style={styles.toolbar}>
<Image
resizeMode='contain'
style={styles.toolbarTitle}
source={require('./Resources/LogoWithDesc.jpg')} />
</View>
<View>
<Image
style={styles.title}
source={require('./Resources/Pot.png')} />
</View>
<View style={styles.searchButton}>
<Button onPress = { this.OpenSecondActivityFunction } title = 'Mission'/>
</View>
<View style={styles.searchButton}>
<Button onPress = { this.OpenThirdActivityFunction } title = 'Available Services'/>
</View>
{
(this.state.isVisible === true) ? Splash_Screen : null
}
</View>
);
}
}
export default ActivityProject = StackNavigator(
{
First: { screen: MainActivity, navigationOptions:{header:null} },
Mission: { screen: MissionActivity },
SearchSer: { screen: SearchServices },
autoComp:{screen: }
});
I have created a side menu using drawer navigation. i am getting shadow overlay on the back view. I want to remove the shadow overlay.
Here is what I am getting right now. you see that I am getting a shadow overlay over my view when the drawer is open.
Here is what I want I want the view to be no shadow over the view.
please find below my code which creates a side menu using drawer navigation.
// Drawer.js
import React, { Component } from 'react';
import { View } from 'react-native';
import { DrawerNavigator } from 'react-navigation';
import Home from './AppNavigation';
import { SideMenu } from "./../Common/UIComponents";
import { widthScale } from "./../Common/Utils/Scaling";
export default DrawerStack = DrawerNavigator({
Home: { screen: Home },
MyAccount: { screen: () => <View /> },
MessageToBigFm: { screen: () => <View /> },
MeetTheMJs: { screen: () => <View /> },
Videos: { screen: () => <View /> },
AboutUs: { screen: () => <View /> },
ContactUs: { screen: () => <View /> },
TermsAndConditions: { screen: () => <View /> }
}, {
contentComponent: SideMenu,
drawerWidth: widthScale(320),
drawerBackgroundColor: "transparent",
style: { backgroundColor: "transparent", opacity: 0, shadowOpacity: 0, shadowColor: "transparent" }
});
Side menu js file
// SideMenu.js
import React, { Component } from "react";
import { View, Text, ScrollView, Platform } from "react-native";
import { NavigationActions } from "react-navigation";
import style from "./style";
import SideMenuHeader from "./SideMenuHeader";
import { ListFlat } from "./../../UIComponents";
import SideMenuData from "./SideMenuData";
import SideMenuCell from "./SideMenuCell";
import NavigationUtil from "./../../Utils/NavigationUtil";
class SideMenu extends Component {
constructor(props) {
super(props);
this.navigateToScreenWithIndex = this.navigateToScreenWithIndex.bind(this);
this.renderItemSeperator = this.renderItemSeperator.bind(this)
}
navigateToScreenWithIndex(index) {
const routeData = SideMenuData[index];
if (!routeData) {
return null;
}
const routeKey = routeData.navigationKey;
if (routeKey === null) {
return;
}
const navigateAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: routeKey })
]
});
this.props.navigation.dispatch(navigateAction);
}
renderItemSeperator({ leadingItem }) {
if (leadingItem.key === 4) {
return <View style={style.seperator} />
} else {
return null;
}
}
render() {
return (
<View style={style.container}>
{Platform.OS === "ios" && <View style={style.statusBar} />}
<View style={style.listContainer}>
<ListFlat
horizontal={false}
renderHeader={() => <SideMenuHeader />}
data={SideMenuData}
CellComponent={SideMenuCell}
otherProps={{ onCellPress: this.navigateToScreenWithIndex }}
renderSeparator={this.renderItemSeperator}
/>
</View>
</View>
);
}
}
export default SideMenu;
I had a similar situation where React's Material UI adds a "MuiBackdrop-root" class div upon showing the Drawer. This was on web, but a mobile version of styled-components exists for React-Native--it could work.
Using the styled-components library, I used a CSS property similar to the following to hide it using "display: none". You have to use the > to directly target the element.
Something like this:
const MyDrawer = styled(Drawer)`
& > .MuiBackdrop-root {
display: none;
}
`;
Hope this helps you!
My React Js skills are very basic,What I want to get is when I click on a category, I show a list of posts of the category selected in a new screen in this case is PostsScreen.
The problem is that i get the itemId null.
I don't know what i'm doing wrong.
These are my screens and the routes component
Categories Screen
import React, {Component} from 'react';
import { NavigationActions, DrawerNavigator, StackNavigator } from 'react-navigation';
import{Dimensions, Button, View, SafeAreaView, FlatList, ActivityIndicator, TouchableOpacity } from 'react-native';
export default class WGoals extends Component {
static navigationOptions = {
title: 'Categories'
};
navigateToScreen = (route, params) => () => {
const navigateAction = NavigationActions.navigate({
routeName: route,
params: params
});
this.props.navigation.dispatch(navigateAction);
}
constructor(props)
{
super(props);
this.state = {
isLoading: true,
}
}
render() {
return (
<Container style={styles.background_general}>
<TouchableOpacity onPress={this.navigateToScreen('PostsScreen', itemId = '1')} >
<Text>Category 1</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.navigateToScreen('PostsScreen', itemId = '2')} >
<Text>Category 2</Text>
</TouchableOpacity>
</Container>
);
}
}
Posts Screen
import React, {Component} from 'react';
import { NavigationActions, DrawerNavigator, StackNavigator } from 'react-navigation';
import{Dimensions, View, SafeAreaView, FlatList, ActivityIndicator } from 'react-native';
export default class Posts extends Component {
static navigationOptions = {
title: 'Posts'
};
render() {
const { params } = this.props.navigation.state;
const itemId = params ? params.itemId : null;
return (
<Container style={styles.background_general}>
<Text>Details Screen</Text>
<Text>itemId: {JSON.stringify(itemId)}</Text>
</Container>
);
}
}
Routes
import React from 'react';
import CategoriesScreen from '../screens/Categories';
import PostsScreen from '../screens/Posts';
import SideMenu from './SideMenu';
import {DrawerNavigator, StackNavigator} from 'react-navigation'
const navigationOptions = {
navigationOptions: {
headerStyle: {
backgroundColor: '#f39c12',
},
headerTitleStyle: {
textAlign: 'center',
alignSelf: 'center',
fontSize: 20,
color: '#fff',
fontWeight: 'bold'
}
}
};
const leftIcon = (navigation, icon) => <Icon
name={icon}
style={{marginLeft: 20}}
size={20}
color="white"
onPress={() => navigation.navigate('DrawerOpen')}
/>;
const rightIcon = (navigation, icon) => <Icon
name={icon}
style={{marginLeft: 20}}
size={30}
color="white"
onPress={() => navigation.navigate('CategoriesScreen')}
/>;
const CategoriesScreenStack = StackNavigator (
{
Categories: {
screen: CategoriesScreen,
navigationOptions: ({navigation}) => ({
drawerIcon: ({tintColor}) => (<Icon name="home" size={24} style={{color: '#f39c12'}} />),
headerLeft: leftIcon(navigation, 'menu')
})
}
},
navigationOptions
);
const PostsScreenStack = StackNavigator(
{
PostsScreen: {
screen: PostsScreen,
navigationOptions: ({ navigation }) => ({
drawerIcon: ({ tintColor }) => (<Icon name="user" size={24} style={{ color: tintColor }} />),
headerLeft: leftIcon(navigation, 'menu')
})
}
},
navigationOptions
);
export default DrawerNavigator({
CategoriesScreen: {
screen: CategoriesScreenStack
},
PostsScreen: {
screen: PostsScreenStack
},
}, {
contentComponent: SideMenu,
drawerWidth: width * .7,
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
});
You want to pass itemId in an object to navigateToScreen, since you are accessing params as an object (params.itemId) in WorkoutsGoalsList, currently it is undefined.
Also, onPress expects a function reference. As it is now, you are actually calling the function so this.navigateGateToScreen will be called on every render. Check out the bind documentation, bind allows you to create a new function with a specific list of arguments:
render () {
return (
<Container style={styles.background_general}>
<TouchableOpacity
onPress={this.onPress.bind(this, '1')}
>
<Text>Category 1</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.onPress.bind(this, '2')}
>
<Text>Category 2</Text>
</TouchableOpacity>
</Container>
);
};
onPress = (id) => {
this.navigateToScreen('PostsScreen', { itemId: id })
};
You also do not need to curry your navigateToScreen function:
navigateToScreen = (route, params) => { // remove curry here
const navigateAction = NavigationActions.navigate({
routeName: route,
params: params,
});
this.props.navigation.dispatch(navigateAction);
};
Your props will look something like this:
this.props = {
navigation: {
state: {
params: {
itemId: '1',
}
}
}
};
It's less than optimal to bind in render because a new function will be created on every render call. A better way to structure the code is to create a dedicated component and pass an itemId and onPress function:
WGoals
export default class WGoals extends Component {
static navigationOptions = {
title: 'Categories',
};
navigateToScreen = (route, params) => {
const navigateAction = NavigationActions.navigate({
routeName: route,
params: params,
});
this.props.navigation.dispatch(navigateAction);
};
constructor(props) {
super(props);
this.state = {
isLoading: true,
};
}
render() {
return (
<Container style={styles.background_general}>
<Category name='Category1' onPress={this.navigateToScreen} itemId='1' />
<Category name='Category2' onPress={this.navigateToScreen} itemId='2' />
</Container>
);
}
}
Category
export default class Category extends Component {
render () {
const { name } = this.props;
return (
<TouchableOpacity
onPress={this.handlePress}
>
<Text>{name}</Text>
</TouchableOpacity>
);
}
handlePress = () => {
const { itemId, onPress } = this.props;
onPress('PostsScreen', { itemId: itemId });
}
}
In PostsScreens, you need to render itemId in a string or you can render the value of the variable by wrapping it in curly brackets ({itemId}). Below, I'm rendering it as a string and inserting the value of itemId into the string. Check out the template literal docs for more info on the syntax:
export default class Posts extends Component {
static navigationOptions = {
title: 'Posts',
};
render() {
const { params } = this.props.navigation.state;
const itemId = params ? params.itemId : null;
return (
<Container style={styles.background_general}>
<Text>'Details Screen'</Text>
<Text>`itemId: ${itemId}`</Text>
</Container>
);
}
}
I'm using react-navigation to navigte my android app, I use react-navigation with redux.
App.js:
const AppRouteConfigs = {
Home: {
screen: HomeView
},
Completed: {
screen: CompletedView
}
}
export const AppNavigator = TabNavigator(AppRouteConfigs,{
tabBarPosition: 'bottom',
tabBarOptions: {
showIcon: true
}
});
#connect(state=>({
nav: state.nav
}))
class App extends Component {
componentDidMount(){
SplashScreen.hide();
}
render(){
return (
<AppNavigator navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav
})}/>
)
}
}
export default App;
reducer:
const initialNavState = {
index: 1,
routes: [
{key: 'InitB',routeName: 'Completed'},
{key: 'InitA',routeName: 'Home'}
]
}
export default function(state=initialNavState,action){
switch(action.type) {
case 'Login':
return AppNavigator.router.getStateForAction(NavigationActions.back(),state);
case 'Logout':
return AppNavigator.router.getStateForAction(NavigationActions.navigate({routeName: 'Completed'}),state)
default:
return state;
}
}
HomeView:
#connect(state=>({
todos: state.todos
}))
export default class HomeView extends Component{
constructor(props){
super(props);
}
static navigationOptions = {
tabBarLabel: 'Home View',
tabBarIcon: ({tintColor})=>(
<Icon name="rocket" size={15} color="#900" />
)
}
handleClick = ()=>{
this.props.dispatch(NavigationActions.navigate({routeName: 'Completed'}))
}
render(){
return (
<View>
<Text>Hey,I'm home page</Text>
<Button onPress={this.handleClick} title="go to completed"/>
<Icon name="rocket" size={30} color="#900" />
</View>
)
}
}
in the Home view, I want to navigate to Completed view,
this.props.dispatch(NavigationActions.navigate({routeName: 'Completed'}))
doesn't work, I don't know why.
this.props.navigation.dispatch(NavigationActions.navigate({routeName: 'Completed'}))
doesn't work, either.
Try this one:
render() {
const { navigate } = this.props.navigation
return (
<View>
<Button
onPress={() => navigation.navigate('Completed')}
title='Completed'
/>
</View>
)
}