Problem accessing navigation parameters in consuming component - react-native

I am having difficulty of accessing parameters passed from component named NewsPageScreen.js. the parameters are passed to BrowserScreen.js. My app has Main Navigator component called MainTabNavigator.js that displays Bottom Tabs. The 'News' tab is connected to NewsPageScreen.js and this is where I am passing the the parameter to BrowserScreen.js but for some reason I am unable to access the parameters BrowserScreen.js, Can anyone help me see what I am getting wrong because it is giving me undefined. All my files are shown below:
MainTabNavigator.js
import React from 'react';
import { Ionicons } from '#expo/vector-icons';
import { TabBarBottom } from 'react-navigation';
import {createBottomTabNavigator} from 'react-navigation-tabs'
import { createAppContainer } from 'react-navigation'
import { createStackNavigator } from 'react-navigation-stack'
import NewsPageScreen from '../screens/NewsPageScreen';
import FavouriteScreen from '../screens/FavouriteScreen';
import SettingScreen from '../screens/SettingScreen';
import BrowserScreen from '../screens/BrowserScreen';
const Colors = {
tabIconDefault: '#ccc',
tabIconSelected: '#2f95dc'
}
const tabNavigator = createBottomTabNavigator({
News: createStackNavigator({
News: NewsPageScreen,
navigationOptions: ({ navigation }) => ({
title: 'News'
}),
}),
Favourite: createStackNavigator({
Favourite: FavouriteScreen,
navigationOptions: ({ navigation }) => ({
title: 'Favourite'
}),
}),
Setting: createStackNavigator({
Setting: SettingScreen,
navigationOptions: ({ navigation }) => ({
title: 'Setting'
}),
}),
Browser: createStackNavigator({
Browser: BrowserScreen,
navigationOptions: ({ navigation }) => ({
title: navigation.state.params.title
}),
}),
}, {
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused }) => {
const { routeName } = navigation.state;
let IconComponent = Ionicons ;
let iconName;
switch (routeName) {
case 'News':
//iconName = `ios-information-circle`;
iconName = focused ? 'ios-information-circle' : 'ios-information-circle-outline'
break;
case 'Favourite':
iconName = `ios-link`;
break;
case 'Setting':
iconName = `ios-options`;
}
return
<IconComponent
name={iconName}
size={28}
style={{marginBottom: -3}}
//color={tintColor}
color={focused ? Colors.tabIconSelected : Colors.tabIconDefault}
/>
},
}),
tabBarComponent: TabBarBottom,
tabBarPosition: 'bottom',
animationEnabled: false,
swipeEnabled: false,
});
const MainTabNavigator = createAppContainer(tabNavigator)
export default MainTabNavigator;
NewsPageScreen.js
import React, { Component } from 'react'
import { TouchableOpacity, View,StyleSheet,Text,SafeAreaView,} from 'react-native';
export default class NewsPageScreen extends Component {
state = {
links: [
{
title: 'Smashing Magazine',
url: 'https://www.smashingmagazine.com/articles/'
},
{
title: 'CSS Tricks',
url: 'https://css-tricks.com/'
},
],
};
handleButtonPress = (button) => {
const { url, title } = button;
this.props.navigation.navigate('BrowserScreen', { url, title });
}
renderButton = (button, index) => {
return (
<TouchableOpacity
key={index}
onPress={() => this.handleButtonPress(button)}
style={styles.button}
>
<Text style={styles.text}>{button.title}</Text>
</TouchableOpacity>
);
}
render() {
return (
<SafeAreaView style={styles.container}>
<View>
<Text style={styles.newsTitle}>Scan The Somali world News</Text>
</View>
<View style={styles.buttonList}>
{this.state.links.map(this.renderButton)}
</View>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
buttonList: {
flex: 1,
justifyContent: 'center',
},
button: {
margin: 10,
backgroundColor: '#c0392b',
borderRadius: 3,
padding: 10,
paddingRight: 30,
paddingLeft: 30,
},
text: {
color: '#fff',
textAlign: 'center',
},
newsTitle: {
color:'#000',
textAlign: 'center',
marginTop: 20
}
});
BrowserScreen.js
import React, { Component } from 'react'
import { WebView } from 'react-native-webview';
export default class BrowserScreen extends Component {
render() {
//console.log(navigation)
const { params } = this.props.navigation.state;
console.log(params)
return (
/**
* use the webview here to display the webpage
*/
<WebView source={{ uri: url }} />
)
}
}
App.js
import { StatusBar } from 'expo-status-bar';
import React, { useState } from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import AppIntroSlider from "react-native-app-intro-slider";
import MainTabNavigatorp from './src/navigation/MainTabNavigator';
export default function App() {
return (
<View style={{flex: 1}}>
<MainTabNavigator />
</View>
);
}
const styles = StyleSheet.create({
MainContainer: {
flex: 1,
paddingTop: 20,
alignItems: 'center',
justifyContent: 'center',
padding: 20
},
slide: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'blue',
},
image: {
width: 220,
height: 220,
marginVertical: 32,
},
description: {
color: 'rgba(255, 255, 255, 0.8)',
textAlign: 'center',
paddingLeft: 10,
paddingRight: 10,
fontSize: 18,
},
title: {
fontSize: 25,
color: 'white',
fontWeight: 'bold',
textAlign: 'center',
},
});

Related

React Native - How to set the drawer navigation content on the particular tab based on drawer item selection?

What i want to achieve is there are 2 tabs in my app
1) Home => On press it shows a simple screen
2) Menu => On press it opens and close drawer based on whether drawer is opened or not.
Drawer has custom content.
It has 4 buttons
1) Accounts
2) Reports
3) Graph
4) List
Selecting on any of the drawer item it should open a respective page in the "Menu" tab navigator space.
So how to manage this kind of navigation?
import React from 'react';
import { View, Text } from 'react-native'
import { createAppContainer, createSwitchNavigator } from 'react-navigation'
import { createStackNavigator } from 'react-navigation-stack'
import ShipmentScreen from '../containers/Shipment/ShipmentScreen';
import LoginScreen from '../containers/Login/LoginScreen';
import ShipmentDetailScreen from '../containers/Shipment/ShipmentDetailScreen';
import AuthLoadingScreen from '../containers/AuthLoadingScreen';
import BarcodeScreen from '../containers/Barcode/BarcodeScreen';
import { createBottomTabNavigator } from 'react-navigation-tabs'
import { createDrawerNavigator } from 'react-navigation-drawer';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import Colors from "../utils/Colors";
import Sidebar from '../components/Sidebar';
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
}
class Data extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Menu Screen</Text>
</View>
);
}
}
const defaultStackNavOptions = {
headerStyle: {
backgroundColor: Platform.OS === 'android' ? Colors.primaryColor : ''
},
headerTitleStyle: {
fontWeight: 'bold',
},
headerBackTitleStyle: {
fontWeight: 'bold',
},
headerTintColor: Platform.OS === 'android' ? Colors.lightColor : Colors.primaryColor,
headerTitle: 'SFL'
};
const TabNavigator = createBottomTabNavigator({
Home: {
screen: HomeScreen,
navigationOptions: {
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor }) => (
<View>
<MaterialCommunityIcons style={{ color: tintColor }} size={25} name={'home'} />
</View>),
},
},
Menu: {
screen: sideDrawer,
navigationOptions: {
tabBarLabel: 'Menu',
tabBarIcon: ({ tintColor }) => (
<View>
<MaterialCommunityIcons style={{ color: tintColor, }} size={25} name={'menu'} />
</View>),
},
},
},
{
initialRouteName: "Home",
activeColor: Colors.activeTabColor,
inactiveColor: Colors.inactiveTabColor,
barStyle: {
backgroundColor: Colors.grayColor
},
tabBarOptions: {
style: {
borderTopColor: 'transparent',
shadowColor: Colors.darkColor,
shadowOpacity: 1,
shadowRadius: 30,
shadowOffset: {
height: 10,
width: 10
},
elevation: 5
},
labelStyle: {
fontSize: 12,
fontWeight: 'bold'
},
tabStyle: {
paddingVertical: 5
}
}
},
);
const sideDrawer = createDrawerNavigator(
{
ScreenA: { screen: Data },
ScreenB: { screen: Data },
ScreenC: { screen: Data }
},
{
drawerPosition: 'right',
contentComponent: Sidebar,
}
)
export default AppContainer = createAppContainer(TabNavigator)
How can i will be able to achieve this?
can anyone suggest a workaround solution?
Thanks.

How do I solve this: 'TypeError: undefined is not an object (evaluating '_this.props.navigationProps.toggleDrawer')'

A few days into React-Native, I am trying to implement a navigation drawer in my app.
However, I am not able to solve the error TypeError: undefined is not an object (evaluating '_this.props.navigationProps.toggleDrawer') when I tap the TouchableOpacity component that should trigger the drawer.
Following is the code I have used:
Header.js
import React, { Component } from 'react';
import { View, StyleSheet, Image, TouchableOpacity, Platform } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createDrawerNavigator } from 'react-navigation-drawer';
import { createStackNavigator } from 'react-navigation-stack';
import Screen1 from '../pages/screen1';
import Screen2 from '../pages/screen2';
import Screen3 from '../pages/screen3';
import logo from '../assets/logo.png';
import profileView from '../assets/profileIcon.png';
import menuDots from '../assets/3DotsMenu.png';
import { StatusBarHeight } from '../components/StatusBarHeight';
const statusBarHeight = StatusBarHeight
class Header extends Component {
toggleDrawer = () => {
this.props.navigationProps.toggleDrawer();
};
render() {
return (
<View>
<CreateDrawer />
<View style={styles.header} />
<View style={styles.headerContainer}>
<View style={styles.imageHolder}>
<TouchableOpacity
activeOpacity={0.6}
onPress={this.toggleDrawer.bind(this)}
>
<View>
<Image style={styles.menu} source={menuDots} />
</View>
</TouchableOpacity>
<TouchableOpacity activeOpacity={0.6}>
<View>
<Image style={styles.logo} source={logo} />
</View>
</TouchableOpacity>
<TouchableOpacity activeOpacity={0.6}>
<View>
<Image style={styles.profile} source={profileView} />
</View>
</TouchableOpacity>
</View>
</View>
</View>
);
};
}
const FirstActivity_StackNavigator = createStackNavigator({
First: {
screen: Screen1,
navigationOptions: ({ navigation }) => ({
title: 'Demo Screen 1',
headerLeft: () => <Header navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
}
,
{
headerMode: "none"
}
);
const Screen2_StackNavigator = createStackNavigator({
Second: {
screen: Screen2,
navigationOptions: ({ navigation }) => ({
title: 'Demo Screen 2',
headerLeft: () => <Header navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
},
{
headerMode: "none"
}
);
const Screen3_StackNavigator = createStackNavigator({
Third: {
screen: Screen3,
navigationOptions: ({ navigation }) => ({
title: 'Demo Screen 3',
headerLeft: () => <Header navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const DrawerNavigator = createDrawerNavigator({
Screen1: {
screen: FirstActivity_StackNavigator,
navigationOptions: {
drawerLabel: 'Demo Screen 1',
},
},
Screen2: {
screen: Screen2_StackNavigator,
navigationOptions: {
drawerLabel: 'Demo Screen 2',
},
},
Screen3: {
screen: Screen3_StackNavigator,
navigationOptions: {
drawerLabel: 'Demo Screen 3',
},
},
});
const styles = StyleSheet.create({
header: {
width: '100%',
height: statusBarHeight,
backgroundColor: '#E6E3E2',
flexDirection: 'row',
},
headerContainer: {
height: 60,
backgroundColor: '#E6E3E2',
justifyContent: 'center',
alignItems: 'center'
},
imageHolder: {
flexDirection: "row",
justifyContent: 'space-between',
width: '95%'
},
menu: {
marginTop: 15,
width: 27,
height: 19,
resizeMode: "stretch"
},
logo: {
width: 140,
height: Platform.OS === 'ios' ? 50 : 50,
},
profile: {
marginTop: 3,
height: 38,
width: 35
}
});
const CreateDrawer = createAppContainer(DrawerNavigator);
export default Header;
App.js
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
import Header from './components/Header';
export default class App extends Component {
render() {
return (
<View style={{flex:1}} >
<View style={{backgroundColor: 'blue'}}>
<Header />
</View>
</View>
);
}
}
Use export default withNavigation(Header); while exporting for a stack of navigations.

react-native-autocomplete result list not touchable

I have this implementation of a screen
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { Icon, View, Text, ListItem } from 'native-base';
import { createMaterialTopTabNavigator } from 'react-navigation';
import { connect } from 'react-redux';
import Autocomplete from 'native-base-autocomplete';
import EventsResults from './EventsResults';
import VehiclesResults from './VehiclesResults';
import { performSearch } from '../actions/search';
import Colors from '../../../util/Colors';
import GlobalStyle from '../../../util/GlobalStyle';
const styles = StyleSheet.create({
autocompleteContainer: {
zIndex: 800
}
});
const mapStateToProps = ({ searchResults }) => ({
searchResults
});
const SearchTabNavigatorStack = createMaterialTopTabNavigator(
{
EventsTab: {
screen: EventsResults,
navigationOptions: { tabBarLabel: 'Events' }
},
VehiclesTab: {
screen: VehiclesResults,
navigationOptions: { tabBarLabel: 'Vehicles' }
}
},
{
initialRouteName: 'EventsTab',
navigationOptions: () => ({
tabBarVisible: true
}),
swipeEnabled: true,
tabBarOptions: {
upperCaseLabel: false,
activeTintColor: Colors.defaultPrimaryColor,
inactiveTintColor: Colors.defaultPrimaryColor,
indicatorStyle: {
backgroundColor: Colors.defaultPrimaryColor,
},
tabStyle: {
height: 48,
alignItems: 'center',
justifyContent: 'center',
},
style: {
backgroundColor: Colors.primaryBackgroundColor,
},
statusBarStyle: 'light-content',
},
}
);
const filterData = (query) => {
const cars = [];
cars.push({ text: 'Chevrolet Trailblazer 2011' });
cars.push({ text: 'Chevrolet Spark 2011' });
cars.push({ text: 'Chevrolet Silverado 2011' });
cars.push({ text: 'Ford Explorer 2010' });
cars.push({ text: 'Ford Escape 2012' });
cars.push({ text: 'Ford Ecosport 2014' });
const result = (query === null || query.trim() === '') ? [] : cars.filter(car => car.text.indexOf(query) !== -1);
return result;
};
class HeaderComponent extends Component {
constructor(props) {
super(props);
this.state = { text: null };
}
render() {
const data = filterData(this.state.text);
return (
<View
style={{
flex: 0,
flexDirection: 'column',
justifyContent: 'space-between',
backgroundColor: Colors.primaryBackgroundColor
}}
>
<View
style={{
flex: 0,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
}}
>
<Text style={[GlobalStyle.textTitleStyle, { marginLeft: 10 }]}>search</Text>
<Icon active style={{ color: Colors.defaultPrimaryColor, margin: 10 }} name='ios-close' />
</View>
<View
style={{
flex: 0,
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'center',
backgroundColor: Colors.defaultPrimaryColor,
marginLeft: 10,
marginRight: 10
}}
>
<Autocomplete
data={data}
containerStyle={styles.autocompleteContainer}
style={{ color: Colors.searchTextInput, backgroundColor: 'white' }}
onChangeText={(text) => this.setState({ text })}
renderItem={item => (
<ListItem style={{ zIndex: 900 }} onPress={() => this.setState({ text: item.text })}>
<Text>{item.text}</Text>
</ListItem>
)}
/>
</View>
</View>
);
}
}
const HeaderContainer = connect(mapStateToProps, { performSearch })(HeaderComponent);
class SearchScreen extends Component {
static router = SearchTabNavigatorStack.router;
static navigationOptions = ({ navigation }) => ({
header: <HeaderContainer />
});
render() {
return (
<SearchTabNavigatorStack navigation={this.props.navigation} />
);
}
}
export default connect(mapStateToProps, null)(SearchScreen);
It had to be this way to provide the ui visual representation that was designed (not my idea); the autocomplete component is working, the result list is displayed but the items in the list are not clickable
I supossed the zIndex property should fix this, but to no avail, and i am out of ideas
Any help or suggestions ?

How do I add Redux implementation in my code?

I want to add redux implementation to my simple Login application with some react navigations.
This is my App.js file where I'm importing my AppDrawerNavigator
import React, {Component} from 'react';
import {createAppContainer, createStackNavigator} from 'react-navigation';
import HomeScreen from './screens/HomeScreen.js';
/** Importing navigator */
import AppDrawerNavigator from './drawerNavigator';
class App extends React.Component {
render() {
return <AppContainer />;
}
}
export default App;
const AppStackNavigator = createStackNavigator(
{
Home: {screen: HomeScreen},
Welcome: AppDrawerNavigator
},
{
initialRouteName: 'Home',
headerMode: "none",
}
);
const AppContainer = createAppContainer(AppStackNavigator);
This is my index.js file pointing to my main App.js file
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
Below shows my different screen files.
HomeScreen.js
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
View,
TouchableOpacity,
Alert,
Keyboard,
TextInput,
} from 'react-native';
//HomeScreen
export default class HomeScreen extends React.Component {
constructor(props) {
super(props);
this.state = {username: null, password: null, isPasswordHidden: true, toggleText: 'Show'};
}
handleToggle = () => {
const { isPasswordHidden } = this.state;
if (isPasswordHidden) {
this.setState({isPasswordHidden: false});
this.setState({toggleText: 'Hide'});
} else {
this.setState({isPasswordHidden: true});
this.setState({toggleText: 'Show'});
}
}
//Validate() to check whether the input username is in Mail format
validate = (inputValue) => {
let reg = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/ ; // Regex for Emails
// let reg = /^(\+\d{1,3}[- ]?)?\d{10}$/; // Regex for phone numbers
return reg.test(inputValue);
}
clearText(fieldName) {
this.refs[fieldName].clear(0);
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}></Text>
<TextInput
ref={'input1'}
style={styles.input}
placeholder="Username"
onChangeText={value => this.setState({username: value})}
// placeholderTextColor="Grey"
// maxLength={13} // For Indian phone numbers
// onChangeText={(text) => this.validate(text)}
// value={this.state.username}
/>
<TextInput
ref={'input2'}
style={styles.input}
placeholder="Password"
maxLength={10}
secureTextEntry={this.state.isPasswordHidden}
onChangeText={value => this.setState({password: value})}
// placeholderTextColor="rgb(225,225,225)"
/>
<TouchableOpacity
onPress={this.handleToggle}
>
<Text>{this.state.toggleText}</Text>
</TouchableOpacity>
<View style={{padding: 20}}>
<TouchableOpacity onPress={() => {
if (!this.validate(this.state.username)) {
Alert.alert("Invalid");
Keyboard.dismiss();
} else if (this.state.username === 'vinay#gmail.com' && this.state.password === 'password') {
//Alert.alert("Login Successful");
if(this.state.username && this.state.password){
this.props.navigation.navigate('Welcome', {
username: this.state.username,
password: this.state.password,
});
this.setState({username: ""});
this.setState({password: ""});
}else{
alert("Invalid");
}
Keyboard.dismiss();
this.clearText('input1');
this.clearText('input2');
} else if (this.state.username === null && this.state.password === null) {
Alert.alert("Invalid");
} else {
Alert.alert("Login Failed");
this.clearText('input1');
this.clearText('input2');
Keyboard.dismiss();
}
}}>
<View style={styles.button}>
<Text style={styles.buttonText}>LOGIN</Text>
</View>
</TouchableOpacity>
</View>
</View>
);
}
}
/** Stylesheets Defined **/
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
// backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 40,
margin: 10,
padding: 20
// textAlign: 'center',
},
input:{
// height: 40,
// margin: 10,
width: 260,
backgroundColor: 'lightgrey',
marginBottom: 10,
padding: 10,
color: 'black'
},
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3',
fontWeight: 'bold'
},
buttonText: {
padding: 20,
color: 'white'
}
});
This is the screen ProfileScreen.js
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
Image,
View,
} from 'react-native';
export default class Profile extends Component {
render() {
return(
<View>
<Image
style={styles.image}
source={{uri: 'https://facebook.github.io/react/logo-og.png'}}
/>
</View>
);
}
}
/** Stylesheets Defined **/
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
// backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 40,
margin: 10,
padding: 20
// textAlign: 'center',
},
input:{
// height: 40,
// margin: 10,
width: 260,
backgroundColor: 'lightgrey',
marginBottom: 10,
padding: 10,
color: 'black'
},
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3',
fontWeight: 'bold'
},
buttonText: {
padding: 20,
color: 'white'
},
image: {
width: 200,
height: 200,
margin: 10
}
});
This is the screen SettingsScreen.js
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
View,
} from 'react-native';
export default class Settings extends Component {
render() {
return(
<View style={styles.container}>
<Text>Settings</Text>
</View>
);
}
}
/** Stylesheets Defined **/
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
// backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 40,
margin: 10,
padding: 20
// textAlign: 'center',
},
input:{
// height: 40,
// margin: 10,
width: 260,
backgroundColor: 'lightgrey',
marginBottom: 10,
padding: 10,
color: 'black'
},
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3',
fontWeight: 'bold'
},
buttonText: {
padding: 20,
color: 'white'
}
});
This is the screen TabA.js
import React, { Component } from 'react'
import {
View,
Text,
StyleSheet,
} from 'react-native'
export default class TabA extends React.Component {
// static navigationOptions = ({ navigation }) => ({
// title: 'Tab A',
// })
render () {
return (
<View style={styles.container}>
<Text style={styles.text}>I'm Tab A</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#c0392b',
padding: 20,
},
text: {
color: 'white',
fontSize: 40,
fontWeight: 'bold',
}
})
This is the screen TabB.js
import React, { Component } from 'react'
import {
View,
Text,
StyleSheet,
} from 'react-native'
export default class TabB extends React.Component {
// static navigationOptions = ({ navigation }) => ({
// title: 'Tab B',
// })
render () {
return (
<View style={styles.container}>
<Text style={styles.text}>I'm Tab B</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#8e44ad',
padding: 20,
},
text: {
color: 'white',
fontSize: 40,
fontWeight: 'bold',
}
})
This is the screen WelcomeScreen.js
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
View,
} from 'react-native';
export default class WelcomeScreen extends Component {
render() {
const { navigation } = this.props;
const u_name = navigation.getParam('username', 'name');
const p_word = navigation.getParam('password', 'word');
return (
<View style={styles.container}>
<Text style={styles.welcome}>WELCOME</Text>
<Text>USERNAME: {JSON.stringify(u_name)}</Text>
<Text>PASSWORD: {JSON.stringify(p_word)}</Text>
{/* <View style={{padding: 20}}>
<Button style={{margin: 20}}
title="LOGOUT"
onPress={() => this.props.navigation.navigate('Home')}
/>
</View> */}
</View>
);
}
}
/** Stylesheets Defined **/
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
// backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 40,
margin: 10,
padding: 20
// textAlign: 'center',
},
input:{
// height: 40,
// margin: 10,
width: 260,
backgroundColor: 'lightgrey',
marginBottom: 10,
padding: 10,
color: 'black'
},
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3',
fontWeight: 'bold'
},
buttonText: {
padding: 20,
color: 'white'
}
});
Below shows my different navigator files
This is the drawer navigator file drawerNavigator.js
import React, {Component} from 'react';
import {
View,
Button,
SafeAreaView,
} from 'react-native';
import {
createDrawerNavigator,
DrawerItems,
} from 'react-navigation';
import TabA from './screens/TabA.js';
import TabB from './screens/TabB.js';
import WelcomeStackNavigator from './stackNavigator';
class Hidden extends React.Component {
render() {
return null;
}
}
const AppDrawerNavigator = createDrawerNavigator({
Welcome: {
screen: WelcomeStackNavigator,
navigationOptions: {
drawerLabel: <Hidden />
}
},
TabA: { screen: TabA },
TabB: { screen: TabB },
// TabC: { screen: TabC },
},{
contentComponent:(props) => (
<View style={{flex:1}}>
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
<DrawerItems {...props} />
<Button
title="Logout"
onPress={() => {
props.navigation.navigate('Home')
}}
/>
</SafeAreaView>
</View>
),
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle'
})
export default AppDrawerNavigator;
This is the stack navigator file stackNavigator.js
import React, {Component} from 'react';
import Icon from 'react-native-vector-icons/Ionicons';
import {
createStackNavigator,
} from 'react-navigation';
import WelcomeTabNavigator from './tabNavigator';
const WelcomeStackNavigator = createStackNavigator({
WelcomeTabNavigator: WelcomeTabNavigator
},
{
defaultNavigationOptions:({navigation}) => {
return {
headerLeft: (
<Icon
style={{paddingLeft: 20}}
onPress={() => navigation.openDrawer()}
name="md-menu"
size={30}
/>
)
};
}
}
);
export default WelcomeStackNavigator;
This is the tab navigator file tabNavigator.js
import React, {Component} from 'react';
import WelcomeScreen from './screens/WelcomeScreen.js';
import Profile from './screens/ProfileScreen.js';
import Settings from './screens/SettingsScreen.js';
import Icon from 'react-native-vector-icons/Ionicons';
import {
createBottomTabNavigator,
} from 'react-navigation';
const WelcomeTabNavigator = createBottomTabNavigator(
{
Welcome: {
screen: WelcomeScreen,
navigationOptions: {
tabBarIcon: ({tintColor}) => (
<Icon
name="md-home"
size={20}
/>
)
}
},
Profile: {
screen: Profile,
navigationOptions: {
tabBarIcon: ({tintColor}) => (
<Icon
name="md-book"
size={20}
/>
)
}
},
Settings: {
screen: Settings,
navigationOptions: {
tabBarIcon: ({tintColor}) => (
<Icon
name="md-settings"
size={20}
/>
)
}
},
},
{
tabBarOptions: {
activeTintColor: '#fb9800',
inactiveTintColor: '#7e7b7b',
style: { height: 40,backgroundColor: '#fff',borderTopWidth:0.5,borderTopColor: '#7e7b7b' },
labelStyle: {fontSize: 15}
},
// navigationOptions:({navigation}) => {
// const {routeName} = navigation.state.routes[navigation.state.index];
// return {
// headerTitle: routeName
// };
// },
navigationOptions:({navigation}) => {
const {routeName} = navigation.state.routes[navigation.state.index];
return {
headerTitle: routeName,
// headerLeft: (
// <Icon
// style={{paddingLeft: 20}}
// onPress={() => navigation.openDrawer()}
// name="md-menu"
// size={30}
// />
// )
};
}
}
)
export default WelcomeTabNavigator;
How do I structure my project and add redux implementation on this login application?
Have you checked their doc? https://redux.js.org/
also, you can see ignite boilerplate implementation for redux in react native apps https://github.com/infinitered/ignite
It seems like a good practice to have your screen code(jsx) separated from your container code (where you'll have your mapDispatchToProps and your mapStateToProps).
So a good 'flow of information' using redux would look something like this:
Screen + container -> (dispatch) -> actions -> (dispatch) -> reducers -> and then stored in the store.
So to give you an idea of how to implement this, I'll show an example on how to use it for your purpose.
LoginScreen.js
export default class LoginScreen extends Component {
constructor(props) {
super(props);
}
login() {
//Here i'm assuming that you have clicked some kind of button
//to submit the login information that you filled in your text input (username and password)
const { username, password } = this.props;
const loginData = {
username,
password
}
//here you'll be passing it to the dispatchToProps in your container
this.props.login(loginData)
}
}
LoginScreenContainer.js
const mapStateToProps = state => {
...state.userReducer,
}
const mapDispatchToProps = (dispatch) => {
//The function that you called on your screen,
//and then we'll be dispatching the loginData to the user_actions
login: (loginData) => {
dispatch(loginUser(loginData))
},
}
//Dont forget to connect both mapStateToProps and mapDispatchToProps to your screen
export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);
User_Actions.js
export function loginUser(loginData) {
//The code to login would be here, if you are using firebase,
//back4app or any other provider, you would implement the login required here
//Now assuming that the user successfully logged on you would dispatch a success and then store that user in the store
//(just as an example, you can store the username and any other information that you'd like):
if (user) {
dispatch({ type: 'USER_LOGIN', payload: { user } })
} else {
dispatch({ type: 'USER_LOGIN_REJECTED' });
}
}
User_Reducer.js this is your reducer, you can have reducers also to handle the navigation in your app (not recommended though). It's basically a giant switch case that you'll get the dispatch actions.
export default function reducer(state = {
user: null,
}, action) {
const { type, payload } = action
switch (type) {
case 'USER_LOGIN': {
return { ...state, user: payload.user }
}
case 'USER_LOGIN_REJECTED': {
return { ...state, user: null }
}
default: {
return state
}
}
}
Store.js
const rootReducer = combineReducers({
user_reducer,
})
let middleware = [thunk]
if (process.env.NODE_ENV !== 'production') {
middleware = [...middleware, logger] //Logger is an useful library to log your state changes
}
export default createStore(
rootReducer,
undefined,
applyMiddleware(...middleware)
)
App.js and then here you'll wrap your main stackNavigator in the provider tag
import { Provider } from 'react-redux';
import store from './src/redux/store';
render() {
return (
<Provider store={store}>
<RootNavigator />
</Provider>
)
}
Hopefully this helps you understand a basic flow (I'm sure there are other ways to do it) and how to implement redux for your needs.

this.props.navigation.navigate does not work in screen

In my app I have a choose language screen which I have registered in the stackNavigator but I cannot use this.props.navigation.navigate in it
this 'choose language screen' appears on app first launch
this is index.js
import {AppRegistry} from 'react-native';
import App from './App';
import ChooseLanguage from './screens/ChooseLanguage'
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => ChooseLanguage);
this is ChooseLanguage Screen so when pressing the touchable opacity
I am calling this.props.navigation.navigate('AppIntroScreen') but it is not working it is giving me this error:
undefined is not an object (evaluating _this2.props.navigation.navigate)
import React, { Component } from "react";
import {
View,
Text,
StyleSheet,
Image, SafeAreaView, TouchableOpacity,AsyncStorage
} from "react-native";
import {withNavigation} from 'react-navigation'
import i18n from 'i18next';
import { translate } from 'react-i18next';
import NavigationService from './NavigationService';
import AppIntroScreen from './AppIntroScreen'
class ChooseLanguage extends Component {
state = {
isArabic: false,
isEnglish: false,
switchLang: true,
languageSet:false
}
async onChangeLang(lang) {
i18n.changeLanguage(lang);
try {
await AsyncStorage.setItem('#APP:languageCode', lang);
} catch (error) {
console.log(` Hi Errorrrr : ${error}`);
}
console.log(i18n.dir());
this.setState(state => ({
switchLang: !state.switchLang,
}));
}
render() {
const {t,navigation} = this.props;
console.log(navigation)
return (
(this.state.switchLang ? <SafeAreaView style={styles.container}>
<Image source={require('../assets/lang.png')} />
<Text style={{ fontSize: 25, color: '#FF5252', marginTop: 20, fontFamily: 'Hanken-Book' }}>Choose Language</Text>
<View style={{ flexDirection: 'row', justifyContent: 'space-evenly' }}>
<TouchableOpacity onPress={() => this.setState({ isEnglish: true, isArabic: false })} style={{ marginVertical: 20, marginHorizontal: 20, padding: 10, borderBottomColor: this.state.isEnglish ? '#a8a8a8' : '#ffffff', borderBottomWidth: this.state.isEnglish ? 1 : 0 }}>
<Text style={{color:this.state.isEnglish?'#000000':'#A8A8A8'}}>English</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.setState({ isEnglish: false, isArabic: true })} style={{ marginVertical: 20, marginHorizontal: 20, padding: 10,borderBottomColor: this.state.isArabic ? '#a8a8a8' : '#ffffff', borderBottomWidth: this.state.isArabic ? 1 : 0 }}>
<Text style={{color:this.state.isArabic?'#000000':'#A8A8A8'}}>Arabic</Text>
</TouchableOpacity>
</View>
<TouchableOpacity onPress={() =>
{
if(this.state.isArabic){
this.onChangeLang('ar');
this.props.navigation.navigate('AppIntroScreen');
}else if(this.state.isEnglish){
this.onChangeLang('en');
this.props.navigation.navigate('AppIntroScreen');
}else{
alert('Please Choose a language')
}
}
} style={{ backgroundColor: '#FF5252', alignSelf: 'center', padding: 10, width: '40%', marginTop: 15,borderRadius:5 }}>
<Text style={{ color: '#FFF', fontSize: 18, fontWeight: '100', textAlign: 'center', fontFamily: 'Hanken-Book' }}>Let's Start</Text>
</TouchableOpacity>
<View style={{
position: 'absolute',
bottom: 0,
right: 1,
left: 1,
height: 50,
justifyContent: 'center', alignItems: 'center'
}}>
<Image source={require('../assets/l1.png')} style={{ width: 120, height: 25 }} />
</View>
</SafeAreaView>:<AppIntroScreen />)
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
bottom: 20
}
});
export default translate(['chooselanguage'], { wait: true })(ChooseLanguage);
even though I am registering all my screens in the StackNavigator
here is the code of App.js
const TabNav = createBottomTabNavigator({
HomeScreen: {
screen: HomeScreen,
},
Categories: {
screen: Categories,
},
Search: {
screen: Search,
},
Settings: {
screen: Settings,
},
}, {
tabBarOptions: {
activeTintColor: '#ff5252',
inactiveTintColor: 'grey',
style: {
backgroundColor: 'white',
borderTopWidth: 0,
shadowOffset: { width: 5, height: 3 },
shadowColor: 'black',
shadowOpacity: 0.5,
elevation: 5
}
}
})
const StacksOverTabs = createStackNavigator({
Root: {
screen: TabNav,
},
ChooseLanguage:{
screen: ChooseLanguage,
navigationOptions:{
}
},
ListingPerCategory: {
screen: ListingPerCategory,
navigationOptions: {
// title: 'Notifications',
},
},
ListingInformation: {
screen: ListingInformation,
navigationOptions: {}
},
SubscribeScreen: {
screen: SubscribeScreen,
navigationOptions: {}
},
AppIntroScreen: {
screen: AppIntroScreen,
navigationOptions: {}
},
OnboardingScreens: {
screen: OnboardingScreens,
navigationOptions: {}
},
ListingDetail: {
screen: ListingDetail,
navigationOptions: {}
},
Contact: {
screen: ContactScreen,
navigationOptions: {}
},
}, {
headerMode: 'none',
navigationOptions: {
headerVisible: false,
}
});
const WrappedStack = ({ t,navigation }) => {
return <StacksOverTabs screenProps={{ t,navigation}} />;
};
const ReloadAppOnLanguageChange = translate('common', {
bindI18n: 'languageChanged',
bindStore: false,
})(WrappedStack);
class App extends React.Component {
state = { notification: {}, timePassed: false }
componentDidMount() {
OneSignal.init('99471d55-8e89-49ef-a70f-47661c9f952b', { kOSSettingsKeyAutoPrompt: true })
OneSignal.addEventListener('received', this.onReceived);
OneSignal.addEventListener('opened', this.onOpened);
OneSignal.addEventListener('ids', this.onIds);
}
async retrieveItem(key) {
try {
const retrievedItem = await AsyncStorage.getItem(key);
const item = JSON.parse(retrievedItem);
return item;
} catch (error) {
console.log("error");
}
return
}
componentWillUnmount() {
OneSignal.removeEventListener('received', this.onReceived);
OneSignal.removeEventListener('opened', this.onOpened);
OneSignal.removeEventListener('ids', this.onIds);
}
onReceived(notification) {
console.log("Notification received: ", notification);
}
onOpened(openResult) {
console.log('Message: ', openResult.notification.payload.body);
console.log('Data: ', openResult.notification.payload.additionalData);
console.log('isActive: ', openResult.notification.isAppInFocus);
console.log('openResult: ', openResult);
}
onIds(device) {
console.log('Device info: ', device);
}
render() {
this.retrieveItem('appLaunched').then((goals) => {
console.log(goals)
}).catch((error) => {
//this callback is executed when your Promise is rejected
console.log('Promise is rejected with error: ' + error);
});
return <ReloadAppOnLanguageChange />
}
}
export default App;
You can access the navigation prop in any component(deeply nested) by composing withNavigation HOC (not available in v1). It's useful when you cannot pass the navigation prop into the component directly, or don't want to pass it in case of a deeply nested child.
import React from 'react';
import { Button } from 'react-native';
import { withNavigation } from 'react-navigation';
class MyBackButton extends React.Component {
render() {
return <Button title="Back" onPress={() => { this.props.navigation.goBack() }} />;
}
}
// withNavigation returns a component that wraps MyBackButton and passes in the
// navigation prop
export default withNavigation(MyBackButton);