React-Native Welcome Screen on first login - javascript

I am developing a React-Native app in which I want to include a Welcome Screen that shows up after the user logs in, but only on the first time. I have already developed the Welcome Screen with React-Native-App-Intro-Slider and it works fine, but it shows up every time the user opens the app.
This is the code I have at the moment. This is the Welcome.js code:
import { StyleSheet, View, Text, Image, I18nManager, Dimensions } from 'react-native';
import AppIntroSlider from 'react-native-app-intro-slider';
import { TouchableRipple } from 'react-native-paper'
import FastImage from 'react-native-fast-image';
import Icon from 'react-native-vector-icons/FontAwesome5'
import styles from './Welcome.styles';
I18nManager.forceRTL(false);
const slides = [
{
key: 'k1',
title: '',
text:
'',
video: {
'id': 'k1',
'name': '',
'externalUrl': '',
'link': '',
'type': 'video',
'uuid': 'external',
'cover_url': '',
'title-human': '',
'brand-human': '',
},
image: require('../../assets/images/logo.png')
},
{
key: 'k2',
title: 'Step 1:',
text: '',
video: {
'id': 'k2',
'name': '',
'externalUrl': '',
'link': '',
'type': 'video',
'uuid': 'external',
'cover_url': '',
'title-human': '',
'brand-human': '',
},
footer: ''
},
{
key: 'k3',
title: 'Step 2:',
text: 'Connect your music through your speakers',
video: {
'id': 'k3',
'name': '',
'externalUrl': '',
'link': '',
'type': 'video',
'uuid': 'external',
'cover_url': '',
'title-human': '',
'brand-human': '',
},
}, {
key: 'k4',
title: '',
text: '',
video: {
'id': 'k4',
'name': '',
'externalUrl': '',
'link': '',
'type': 'video',
'uuid': 'external',
'cover_url': '',
'title-human': '',
'brand-human': '',
},
},
{
key: 'k5',
title: 'And lastly...',
image: require('../../assets/images/logo.png'),
text: '',
footer: ''
}
];
export default class Welcome extends React.Component {
constructor(props) {
super(props);
this.state = {
show_Main_App: false
}
}
static navigationOptions = { header: null }
on_Done_all_slides = () => {
this.setState({ show_Main_App: true });
};
on_Skip_slides = () => {
this.setState({ show_Main_App: true });
};
_renderItem = ({ item }) => (
<View style={styles.mainContent}>
<Text style={styles.title}>{item.title}</Text>
{item.image == undefined ? (
<>
<View style={styles.videoContainer}>
<FastImage style={styles.videoImage} resizeMode='cover' source={{ uri: item.video.cover_url }} />
<View style={styles.videoDetailsContainer}>
<View style={styles.videoTagContainer}>
<Text style={styles.videoTagText}> </Text>
</View>
<View style={styles.featuredVideoButtonsContainer}>
<TouchableRipple
onPress={() => this.props.navigation.navigate({ routeName: 'VideoPlayer', key: 'videoPlayer', params: { 'item': item.video } })}
rippleColor='rgba(0, 0, 0, .32)'
>
<View style={styles.videoPlayButton}>
<Icon style={styles.videoPlayButtonIcon} name='play-circle' size={100} color='#fff' />
<Text style={styles.videoPlayButtonText}>Play</Text>
</View>
</TouchableRipple>
</View>
</View>
</View>
<Text style={styles.text}>{item.text}</Text>
</>
) : (
<>
<Image source={item.image} style={styles.image} resizeMode='contain' />
<View>
<Text style={styles.text}>
{item.text}
</Text>
<Text style={styles.text}>
{item.footer}
</Text>
</View>
</>
)}
</View>
);
render() {
if (this.state.show_Main_App) {
return (
this.props.navigation.replace('Dashboard')
);
} else {
return (
<AppIntroSlider
renderItem={this._renderItem}
slides={slides}
onDone={this.on_Done_all_slides}
showSkipButton={true}
onSkip={this.on_Skip_slides} />
);
}
}
}
As I said, this works exactly as intended. However, it shows up every time. This is my App.js code:
import { createStackNavigator, createAppContainer, createBottomTabNavigator } from 'react-navigation'
import { View, StatusBar, Text } from 'react-native'
// import FontAwesome from 'react-native-vector-icons/FontAwesome5'
import IconFontawesome from 'react-native-vector-icons/FontAwesome'
import IconMaterial from 'react-native-vector-icons/MaterialCommunityIcons'
import { MenuProvider } from 'react-native-popup-menu';
// screens
import Splashscreen from './src/screens/Splashscreen/Splashscreen'
import ProfileSetup from './src/screens/ProfileSetup/ProfileSetup'
import UserCreation from './src/screens/UserCreation/UserCreation'
import Login from './src/screens/Login/Login'
import Signup from './src/screens/Signup/Signup'
import VideoPlayer from './src/screens/VideoPlayer/VideoPlayer'
import VideoProfile from './src/screens/VideoProfile/VideoProfile'
import AudioProfile from './src/screens/AudioProfile/AudioProfile'
import ForgotPassword from './src/screens/ForgotPassword/ForgotPassword'
import Welcome from './src/screens/Welcome/Welcome'
import WhoWatching from './src/screens/WhoWatching/WhoWatching'
// Tabs
import MenuScreen from './src/screens/TabScreens/MenuScreen/MenuScreen'
import HomeScreen from './src/screens/TabScreens/HomeScreen/HomeScreen'
// import DownloadScreen from './src/screens/TabScreens/DownloadScreen/DownloadScreen' // avega : replaced with devices screen
import DeviceScreen from "./src/screens/TabScreens/DeviceScreen/DeviceScreen";
import SearchScreen from './src/screens/TabScreens/SearchScreen/SearchScreen'
// Menu Screens
import AccountScreen from './src/screens/TabScreens/MenuScreen/AccountScreen/AccountScreen'
import AppSettingsScreen from './src/screens/TabScreens/MenuScreen/AppSettingsScreen/AppSettingsScreen'
import CellularDataUsageScreen from './src/screens/TabScreens/MenuScreen/AppSettingsScreen/CellularDataUsageScreen/CellularDataUsageScreen'
import VideoQualityScreen from './src/screens/TabScreens/MenuScreen/AppSettingsScreen/VideoQualityScreen/VideoQualityScreen'
import HelpScreen from './src/screens/TabScreens/MenuScreen/HelpScreen/HelpScreen'
import ManageProfilesScreen from './src/screens/TabScreens/MenuScreen/ManageProfilesScreen/ManageProfilesScreen'
import MyListScreen from './src/screens/TabScreens/MenuScreen/MyListScreen/MyListScreen'
import PrivacyScreen from './src/screens/TabScreens/MenuScreen/PrivacyScreen/PrivacyScreen'
import configureStore from "./src/state/store";
import {Provider} from "react-redux";
import {Root} from "native-base";
import DeviceProfile from "./src/screens/DeviceProfile/DeviceProfile";
import DeviceEnroll from "./src/screens/DeviceEnroll/DeviceEnroll";
const DashboardTabNavigator = createBottomTabNavigator(
{
HomeScreen: HomeScreen,
SearchScreen: SearchScreen,
DeviceScreen: DeviceScreen,
MenuScreen: MenuScreen
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'MenuScreen') {
iconName = `menu`
} else if (routeName === 'HomeScreen') {
iconName = `home`
} else if (routeName === 'DeviceScreen') {
iconName = `television`;
} else if (routeName === 'SearchScreen') {
iconName = `thermometer`
}
// return <IconFontawesome name={iconName} size={30} color={focused ? '#fff' : '#c0d3d6'} />
return <IconMaterial name={iconName} size={30} color={focused ? '#fff' : '#c0d3d6'} />
},
tabBarLabel: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let labelName;
if (routeName === 'MenuScreen') {
labelName = `Menu`
} else if (routeName === 'HomeScreen') {
labelName = `Showcase`
} else if (routeName === 'DeviceScreen') {
labelName = `Devices`
} else if (routeName === 'SearchScreen') {
labelName = `Store`
}
return <Text style={focused ? { textAlign: 'center', fontSize: 11, color: '#fff', fontWeight: '600', marginTop: -5, marginBottom: 5 } : { textAlign: 'center', fontSize: 11, marginTop: -5, marginBottom: 5, color: '#C0D3D6' }}>{labelName}</Text>
}
}),
tabBarOptions: {
activeTintColor: '#ff3402',
inactiveTintColor: '#eaeaea',
style: {
backgroundColor: '#00A5AC',
height: 65
},
labelStyle: {
color: '#fff'
}
},
initialRouteName: 'HomeScreen',
navigationOptions: {
header: null
}
}
)
const AppNavigator = createStackNavigator(
{
Splashscreen: Splashscreen,
UserCreation: UserCreation,
Login: Login,
Signup: Signup,
ProfileSetup: ProfileSetup,
Dashboard: DashboardTabNavigator,
Account: AccountScreen,
AppSettings: AppSettingsScreen,
VideoQuality: VideoQualityScreen,
CellularDataUsage: CellularDataUsageScreen,
Help: HelpScreen,
ManageProfiles: ManageProfilesScreen,
MyList: MyListScreen,
Privacy: PrivacyScreen,
VideoPlayer: VideoPlayer,
VideoProfile: VideoProfile,
AudioProfile: AudioProfile,
//AudioPlayer: AudioPlayer
ForgotPassword: ForgotPassword,
WhoWatching: WhoWatching,
DeviceProfile: DeviceProfile,
DeviceEnroll: DeviceEnroll,
Welcome: Welcome
},
{
initialRouteName: 'Splashscreen',
navigationOptions: {
header: null
}
}
);
const AppContainer = createAppContainer(AppNavigator)
export default class App extends React.Component {
store = configureStore();
render () {
return (
<Provider store={this.store}>
<Root>
<MenuProvider>
<View style={{ flex: 1 }}>
<AppContainer />
<StatusBar translucent backgroundColor='transparent' barStyle='light-content' />
</View>
</MenuProvider>
</Root>
</Provider>
)
}
}
As you can see the first page is a Splashscreen, that then should lead to the guided tour. This is the Splashscreen.js code:
import { View, Image, ActivityIndicator } from 'react-native'
import styles from './Splashscreen.styles'
import AuthHelperMethods from "../../api/auth-helper-methods";
export default class Splashscreen extends Component {
static navigationOptions = { header: null }
componentDidMount () {
setTimeout(() => {
AuthHelperMethods.loggedIn().then((isLoggedIn) => {
if (isLoggedIn) {
this.props.navigation.replace('Welcome')
} else {
this.props.navigation.replace('UserCreation')
}
})
}, 500)
}
state={
loading: true
};
render () {
return (
<View style={styles.container}>
<Image style={styles.logo} resizeMode='contain' source={require('../../assets/images/logo.png')} />
<ActivityIndicator size={50} color='#00b2ba' />
</View>
)
}
}
I'm not really sure how to start conceptualizing the idea of this component only showing up either on first-time login, or at least once per login instead of every time the app is used.
Any ideas how to go about it?

You can simply use localStorage. You will have to do some conditional rendering. Whenever user launches the app, you will have to do something like localStorage.setItem('firstTime', false). So, next time when user launches the app, all you need is check if localStorage.getItem('firstTime') === false, if it is false, you render your login page.

The easiest way is probably using asyncStorage (https://facebook.github.io/react-native/docs/asyncstorage)
After installing it import it like:
import AsyncStorage from '#react-native-community/async-storage';
or
import {AsyncStorage} from 'react-native' //Deprecated, will be removed in the future
After you've showed the user the welcome screen, store the data inside asyncStorage:
storeData = async () => {
try {
await AsyncStorage.setItem('welcomeScreenSeen', 'true')
} catch (e) {
// saving failed
}
}
After that, ever login would check that variable and if it's false, just skip your welcomeScreen.
then inside your isLoggedInIf it would be:
if (isLoggedIn) {
this.props.navigation.replace(this.getData("welcomeScreenSeen")?'ScreenDifferentFromWelcome':'Welcome')
}
where getData would be:
getData = async (key) => {
try {
const value = await AsyncStorage.getItem(key)
return value
} catch(e) {
// error reading value
}

You can use Shared Preferences to check if it is the first login.
Simply store a boolean like showWelcomeScreen when the welcome screen was shown.
On startup you can check the shared preferences and decide wheter to show or not to show the screen.
For more information check: Shared Preferences

Related

View config getter callback for component 'H' must be a function (received undefined)

Error is:
Invariant Violation: View config getter callback for component 'H' must be a function (received undefined)
I'm using react-native to make application and error happens when I clicked login button in MainLogin.js file. (It has to move to mainpage when clicking login button in login page)
I searched a lot but cannot know what is component 'H'.
attatched index.js (src/screens/index.js) and MainLogin.js (src/screens/MainLogin.js)
<index.js>
import React from 'react';
import {
Text
} from 'react-native';
import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import { createBottomTabNavigator } from "react-navigation-tabs";
import LoginScreen from './MainLogin';
import HomeScreen from './MainPage';
import DiaryScreen from './Diarymemo';
import StatScreen from './MoodStatistics';
import CommuScreen from './Community';
import StoreScreen from './Store';
const HomeStack = createStackNavigator(
{
HomeScreen
},
{ defaultNavigationOptions : ({navigation}) => ({
title: 'Home'}),
}
);
const DiaryStack = createStackNavigator(
{
DiaryScreen
},
{ defaultNavigationOptions : ({navigation}) => ({
title: 'Diary'}),
}
);
const StatStack = createStackNavigator(
{
StatScreen
},
{ defaultNavigationOptions : ({navigation}) => ({
title: 'Stat'}),
}
);
const CommunityStack = createStackNavigator(
{
CommuScreen
},
{ defaultNavigationOptions : ({navigation}) => ({
title: 'Network'}),
}
);
const StoreStack = createStackNavigator(
{
StoreScreen
},
{ defaultNavigationOptions : ({navigation}) => ({
title: 'Store'}),
}
);
const TabNavigator = createBottomTabNavigator(
InitialRouteName = 'Home',
{
Diary: DiaryStack,
Stat: StatStack,
Home: HomeStack,
Network: CommunityStack,
Store: StoreStack,
},
{
defaultNavigationOptions: ({navigation}) => ({
tabBarIcon: ({focused, horizontal, tintColor}) => {
const {routeName} = navigation.state;
let icon = "▲";
if(routeName === 'Diary'){
icon = "📓";
} else if(routeName === 'Stat'){
icon = "📊"
} else if(routeName === 'Home'){
icon = "🍎"
} else if(routeName === 'Network'){
icon = "👫"
} else if(routeName === 'Store'){
icon = "🛍"
}
// can use react-native-vector-icons
// <Icon name={iconName} size={iconSize} color={iconColor} />
return <Text style={{color: focused && "#46c3ad" || "#888"}}>{icon}</Text>
}
}),
lazy: false,
tabBarOptions: {
activeTintColor: "#46c3ad",
inactiveTintColor: "#888",
},
}
);
const AppStack = createStackNavigator(
{
LoginScreen: LoginScreen,
TabNavigator: {
screen: TabNavigator,
navigationOptions: ({navigation}) => ({
headerShown: false,
}),
},
}
);
export default createAppContainer(AppStack);
<MainLogin.js>
import React, {Component} from 'react';
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet
} from 'react-native';
import {widthPercentageToDP as wp, heightPercentageToDP as hp} from 'react-native-responsive-screen';
export default class LoginScreen extends Component{
static navigationOptions = {
headerShown: false,
};
_doLogin(){
// do something
this.props.navigation.replace('TabNavigator')
}
render(){
return (
<View style={styles.container}>
<View style={styles.titleArea}>
<Text style={styles.title}>MoodiBuddy</Text>
</View>
<View style={styles.formArea}>
<TextInput
style={styles.textForm}
placeholder={"ID"}/>
<TextInput
style={styles.textForm}
placeholder={"Password"}/>
</View>
<View style={styles.buttonArea}>
<TouchableOpacity
style={styles.button}
onPress={this._doLogin.bind(this)}>
<Text style={styles.buttonTitle}>Login</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
paddingLeft: wp('10%'),
paddingRight: wp('10%'),
justifyContent: 'center',
},
titleArea: {
width: '100%',
padding: wp('10%'),
alignItems: 'center',
},
title: {
fontSize: wp('10%'),
},
formArea: {
width: '100%',
paddingBottom: wp('10%'),
},
textForm: {
borderWidth: 0.5,
borderColor: '#888',
width: '100%',
height: hp('5%'),
paddingLeft: 5,
paddingRight: 5,
marginBottom: 5,
},
buttonArea: {
width: '100%',
height: hp('5%'),
},
button: {
backgroundColor: "#46c3ad",
width: "100%",
height: "100%",
justifyContent: 'center',
alignItems: 'center',
},
buttonTitle: {
color: 'white',
},
})

navigator has both navigation and container props error in React Native

So Important : my project was working , bat when i copied them to my backup folder and used after deleting files!!, i got navigation error:
Error: This navigator has both navigation and container props, so it is unclear if it should own its own state. Remove props: "theme" if the navigator should get its state from the navigation prop. If the navigator should maintain its own state, do not pass a navigation prop.
here is my App.js codes:
import { createAppContainer } from "react-navigation"
import AppNavigator from './app/Navi/Navigate'
const AppContainer = createAppContainer(AppNavigator);
export default class App extends React.Component {
render() {
return <AppContainer />
}
}
Where i call AppNavigator from Navigate.js:
const AppNavigator = createStackNavigator({
indexPage : Index,
loginPage : Login,
homePage : TabNavigator
},
{
initialRouteName: "indexPage",
headerMode: 'none',
navigationOptions: {
headerVisible: false,
}
});
export default AppNavigator;
and index.js where error is there (error says it is in line 29 that refers to line 40) :
export default class Index extends React.Component{
componentDidMount(){
this.checker();
}
transfer = (page) => {
if(page == 'Home')
this.props.navigation.navigate('homePage');
else
this.props.navigation.navigate('loginPage');
}
checker = () => {
AsyncStorage.getItem('LoginBoolean')
.then((value) => {
if(value == 'yes')
this.transfer('Home');
else
this.transfer('Login');
})
.catch((error) =>
console.log(error)
);
}
render(){
some rendering tags!
}
}
and no idea what is going on!
Edited
the TabNavigator Compeletly Codes:
that const rednderNav and customTabs are some customization for tab ui
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
import Home from '../Home/home'
import LogOut from '../Logging/logout'
import Search from '../Route/Search'
import Poll from '../Poll/Poll'
import Signate from '../sign/signate'
const renderNav = (name, tintColor) => (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Icon name={name} size={15} style={{color: tintColor}} />
</View>
)
const customTabs = ({ navigation }) => ({
tabBarIcon: ({tintColor }) => {
const { routeName } = navigation.state;
if (routeName === 'LogOut') {
return renderNav('md-log-out', tintColor);
} else if (routeName === 'Home') {
return renderNav('md-planet', tintColor);
} else if (routeName === 'Route') {
return renderNav('md-compass', tintColor);
} else if (routeName === 'Poll') {
return renderNav('ios-checkmark-circle', tintColor);
} else if (routeName === 'Sign') {
return renderNav('hand', tintColor);
}
}
});
const TabNavigator = createBottomTabNavigator({
LogOut : LogOut,
Route : Search,
Home : Home,
Poll : Poll,
Sign : Signate
},
{
defaultNavigationOptions: customTabs,
animationEnabled: true,
swipeEnabled: true,
tabBarPosition: 'bottom',
initialRouteName: 'Poll',
tabBarOptions: {
showLabel: false,
activeTintColor: 'yellow',
inactiveTintColor: '#fff',
style:{
borderTopColor: '#ccc',
borderTopWidth: 3,
backgroundColor:'#191919',
height: 50,
},
activeTabStyle: {
backgroundColor: 'white',
borderBottomWidth: 40,
borderColor: '#6C1D7C'
}
},
});
export default createAppContainer(TabNavigator);
From what I see, you are returning a AppContainer in your TabNavigator file, you should only have one AppContainer for all the application.
So the perfect way can be to return directly the Tabnavigator
export default TabNavigator;
I resolved as follows
original:
export default createAppContainer( createBottomTabNavigator( {
modified:
export default createBottomTabNavigator( {

React Native NetInfo 'connectionChange' event not fired

I have two PoCs I'm working on. 1)RNRestAPI. 2)RNNavigate.
In RNRestAPI index.android.js and index.ios.js both looks like this;
import React, { Component } from 'react';
import {
AppRegistry,
View
} from 'react-native';
import Login from './app/screens/Login/Login';
import About from './app/screens/About/About';
export default class RNRestAPI extends Component {
render() {
return (
<View style={{flex:1}}>
<Login />
</View>
);
}
}
AppRegistry.registerComponent('RNRestAPI', () => RNRestAPI);
Login.js is like this;
import React, { Component } from 'react';
import {
AppRegistry,
View,
TextInput,
StyleSheet,
Button,
Text,
Alert,
TouchableHighlight,
Platform,
Image,
NetInfo,
ProgressBarAndroid,
ProgressViewIOS
} from 'react-native';
import I18n from '../../resources/strings/i18n';
import Colors from '../../resources/styles/colors';
import Dimensions from '../../resources/styles/dimensions';
import Styles from '../../resources/styles/styles';
import Config from '../../config';
export default class Login extends Component {
constructor() {
super();
this.state = {
username:'',
password:'',
buttonLoginDisabled:false,
isConnected:false
}
// I18n.locale = 'en';
}
componentWillMount() {
NetInfo.addEventListener(
'connectionChange',
this.handleConnectivityChange.bind(this)
);
}
componentWillUnmount() {
NetInfo.removeEventListener('connectionChange', handleConnectivityChange);
}
handleConnectivityChange(connectionInfo) {
console.log('First change, type: ' + connectionInfo.type + ', effectiveType: ' + connectionInfo.effectiveType);
if(connectionInfo.type === 'none') {
this.setState({
isConnected:false,
buttonLoginDisabled:true
});
} else {
this.setState({
isConnected:true,
buttonLoginDisabled:false
});
}
}
onLoginClicked() {
var valid = this.validateLoginForm();
if(valid === true) {
this.setState({
buttonLoginDisabled:true
});
this.makeLoginRequest();
} else {
Alert.alert(I18n.t('dialogLoginInvalidTitle'), I18n.t('dialogLoginInvalidMessage'));
}
}
validateLoginForm() {
if(this.state.username === '') {
return false;
}
if(this.state.password === '') {
return false;
}
return true;
}
makeLoginRequest() {
fetch('http://webapitest', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'MobilePlatformId': Config.MobilePlatformId,
'ApplicationId': Config.ApplicationId,
'Version': '1.9.6'
},
body: JSON.stringify({
Username: this.state.username,
Password: this.state.password
})
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
if(responseJson.Token !== null) {
console.log('login successful');
} else {
this.setState({
buttonLoginDisabled:false
});
Alert.alert(I18n.t('dialogInvalidLoginTitle'), I18n.t('dialogInvalidLoginMesage'));
}
})
.catch((error) => {
console.log(eror);
this.setState({
buttonLoginDisabled:false
});
})
}
setUsername(value) {
this.setState({
username:value
});
}
setPassword(value) {
this.setState({
password:value
});
}
onMoreClicked() {
Alert.alert(I18n.t('dialogLearnMoreTitle'), I18n.t('dialogLearnMoreMesage'));
}
getLoginButtonStyle() {
if(this.state.buttonLoginDisabled) {
return styles.buttonLoginDisabled;
} else {
return styles.buttonLogin;
}
}
render() {
return (
<View style={styles.container}>
<View>
<Image source={require('../../resources/images/facilit_logo_welcome.png')}
style={{width:266, height:50, resizeMode:Image.resizeMode.cover}} />
</View>
<View style={styles.wrapperLoginInput}>
<TextInput
keyboardType='default'
placeholder={I18n.t('username')}
returnKeyType='next'
onChangeText={(value) => this.setUsername(value)}
style={Styles.primaryTextInput} />
<TextInput secureTextEntry={true}
placeholder={I18n.t('password')}
onChangeText={(value) => this.setPassword(value)}
style={Styles.primaryTextInput} />
<TouchableHighlight onPress={this.onLoginClicked.bind(this)}
style={{marginTop:(Platform.OS === 'ios') ? 10 : 30}}
underlayColor='#00000000'
disabled={this.state.buttonLoginDisabled}>
<View style={this.getLoginButtonStyle()}>
<Text style={styles.buttonLoginText}>{I18n.t('login')}</Text>
</View>
</TouchableHighlight>
<View style={styles.wrapperLearnMoreLink}>
<TouchableHighlight onPress={this.onMoreClicked.bind(this)}
underlayColor='#00000000'>
<Text style={styles.learnMoreLink}>{I18n.t('learnMore')}</Text>
</TouchableHighlight>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex:1,
backgroundColor:Colors.primaryBlue,
justifyContent:'center',
alignItems:'center'
},
wrapperLoginInput: {
width:300,
marginTop:100
},
buttonLogin: {
backgroundColor:Colors.primaryYellow,
alignItems:'center',
height:Dimensions.primaryButtonHeight,
justifyContent:'center',
borderRadius:Dimensions.primaryButtonBorderRadius,
borderWidth:Dimensions.primaryButtonBorderWidth,
borderColor:Colors.primaryButtonBorderColor,
},
buttonLoginDisabled: {
backgroundColor:Colors.primaryButtonDisabledGray,
alignItems:'center',
height:Dimensions.primaryButtonHeight,
justifyContent:'center',
borderRadius:Dimensions.primaryButtonBorderRadius,
borderWidth:Dimensions.primaryButtonBorderWidth,
borderColor:Dimensions.primaryButtonBorderColor,
},
buttonLoginText: {
fontSize:Dimensions.primaryButtonFontSize,
color:Colors.primaryButtonFontColor
},
wrapperLearnMoreLink: {
alignItems:'center',
marginTop:150,
},
learnMoreLink: {
color:Colors.secondaryTextColor,
textDecorationLine:'underline'
}
});
AppRegistry.registerComponent('Login', () => Login);
The important bits are componentWillMount() and handleConnectivityChange(connectionInfo). They work as expected and my code handles online/offline scenarios.
The second PoC(RNNavigate) is basically a copy of RNRestAPI but with the inclusion of react-navigation https://reactnavigation.org/. I'm basically trying to create the navigation for my app after the user logs in successfully into my app. So accordingly I have done the following modification to my code.
1) Create App.js
import React, { Component } from 'react';
import {
AppRegistry,
View
} from 'react-native';
import Login from './app/screens/Login/Login';
import About from './app/screens/About/About';
import FacilitySearch from './app/screens/FacilitySearch/FacilitySearch';
import { StackNavigator } from 'react-navigation';
export default class RNNavigate extends Component {
render() {
return (
<View style={{flex : 1}}>
<RNNavigateApp />
</View>
);
}
}
const RNNavigateApp = StackNavigator({
Login : {
screen : Login,
navigationOptions : ({navigation}) => ({
header : null
})
},
About : { screen : About },
FacilitySearch : {
screen : FacilitySearch,
navigationOptions : ({
headerLeft : null
})
}
});
AppRegistry.registerComponent('RNNavigate', () => RNNavigate);
2) Modify index.android.js and index.ios.js to;
import './App.js';
Login.js is untouched. But the connectionChange event is no longer fired. Any expert help is much appreciated to guide me figuring out as to why it's no longer fired or educate me on if I have done something wrong in terms of using React Navigate.
For me, the event was not fired because I didn't restart my react-native server after adding <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> in the AndroidManifest.xml.
Kill your server and restart it after then it should fire.

Navigate to root screen from nested stack navigator

i am new to react and trying to learn it by myself , i am facing problem in navigating user back to root screen from nested stck navigator screen .
Here is some of my classes :-
index.android.js :-
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
StatusBar,
View
} from 'react-native';
import {LoginStack} from './login/loginregisterrouter';
import {StackNavigator } from 'react-navigation';
class reactNavigationSample extends Component {
render(){
return (
<LoginStack/>
);
}
}
AppRegistry.registerComponent('MssReactDemo', () => reactNavigationSample);
loginregisterrouter :-
import React from 'react';
import {StackNavigator } from 'react-navigation';
import LoginScreen from './LoginScreen';
import RegisterScreen from './RegisterScreen';
import NavigationContainer from './navigationContainer';
export const LoginStack = StackNavigator({
LoginScreen: {
screen: LoginScreen,
navigationOptions: {
title: 'LoginScreen',
}
},
RegisterScreen: {
screen: RegisterScreen,
navigationOptions: ({ navigation }) => ({
title: 'RegisterScreen',
}),
},NavigationContainer: {
screen: NavigationContainer,
navigationOptions: ({ navigation }) => ({
title: 'NavigationContainer', header: null,
}),
},
});
Navigationcontainer.js :-
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
StatusBar,
View
} from 'react-native';
import {EasyRNRoute,} from '../parent';
import {StackNavigator } from 'react-navigation';
export default class NavigationContainer extends Component {
render(){
return (
<EasyRNRoute/>
);
}
}
parent.js :-
import React, { Component } from 'react';
import {
StyleSheet,
Text,
StatusBar,
View
} from 'react-native';
import App from './app';
import DrawerMenu from './Drawer/drawer-toolbar-android';
import BookmarkView from './Pages/bookmark';
import ClientView from './Pages/client';
import InfoView from './Pages/info';
import SettingsView from './Pages/setting';
import { DrawerNavigator, StackNavigator } from 'react-navigation';
export const stackNavigator = StackNavigator({
Info: { screen: InfoView },
Settings: {screen: SettingsView },
Bookmark: {screen: BookmarkView },
Connections: {screen: ClientView},
}, {
headerMode: 'none'
});
export const EasyRNRoute = DrawerNavigator({
Home: {
screen: App,
},
Stack: {
screen: stackNavigator
}
}, {
contentComponent: DrawerMenu,
contentOptions: {
activeTintColor: '#e91e63',
style: {
flex: 1,
paddingTop: 15,
}
}
});
Drawer-toolbar-android.js :-
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
StatusBar,
View
} from 'react-native';
import { NavigationActions } from 'react-navigation'
import { COLOR, ThemeProvider, Toolbar, Drawer, Avatar } from 'react-native-material-ui';
import Container from '../Container';
import LoginScreen from '../login/LoginScreen';
const uiTheme = {
palette: {
primaryColor: COLOR.green500,
accentColor: COLOR.pink500,
},
toolbar: {
container: {
height: 70,
paddingTop: 20,
},
},
avatar: {
container: {
backgroundColor: '#333'
}
}
};
export default class DrawerMenu extends Component {
constructor(props, context) {
super(props, context);
this.state = {
active: 'people',
};
}
handleLogoutPress = () => {
// AsyncStorage.setItem('SignedUpuser', '');
this.props
.navigation
.dispatch(NavigationActions.reset(
{
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'LoginScreen'})
]
}));
// this.props.navigation.dispatch(NavigationActions.back());
};
_setInfoActive() {
this.setState({ active: 'info' });
}
render() {
return (
<ThemeProvider uiTheme={uiTheme}>
<Container>
<StatusBar backgroundColor="rgba(0, 0, 0, 0.2)" translucent />
<Toolbar
leftElement="arrow-back"
onLeftElementPress={() => this.props.navigation.navigate('DrawerClose')}
centerElement="Menu"
/>
<View style={styles.container}>
<Drawer>
<Drawer.Header >
<Drawer.Header.Account
style={{
container: { backgroundColor: '#fafafa' },
}}
avatar={<Avatar text={'S'} />}
// accounts={[
// { avatar: <Avatar text="H" /> },
// { avatar: <Avatar text="L" /> },
// ]}
footer={{
dense: true,
centerElement: {
primaryText: 'Siddharth',
secondaryText: 'I am DONE now',
},
}}
/>
</Drawer.Header>
<Drawer.Section
style={{
label: {color: '#0000ff'}
}}
divider
items={[
{
icon: 'bookmark-border', value: 'Bookmarks',
active: this.state.active == 'bookmark',
onPress: () => {
this.setState({ active: 'bookmark' });
this.props.navigation.navigate('Bookmark');
},
},
{
icon: 'people', value: 'Connections',
active: this.state.active == 'Connection',
onPress: () => {
this.setState({ active: 'Connection' });
this.props.navigation.navigate('Connections');
},
},
]}
/>
<Drawer.Section
title="Personal"
items={[
{
icon: 'info', value: 'Info',
active: this.state.active == 'info',
onPress: () => {
this.setState({ active: 'info' });
//this.props.navigation.navigate('DrawerClose');
this.props.navigation.navigate('Info');
},
},
{
icon: 'settings', value: 'Settings',
active: this.state.active == 'settings',
onPress: () => {
this.setState({ active: 'settings' });
this.props.navigation.navigate('Settings');
},
},
{
icon: 'logout', value: 'Logout',
active: this.state.active == 'logout',
onPress: () => {
this.handleLogoutPress();
},
},
]}
/>
</Drawer>
</View>
</Container>
</ThemeProvider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
header: {
backgroundColor: '#455A64',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
The above is the stack architecture i am using inside my application and as you can see that my Main screen is LOGIN screen and i do have option for LOGOUT from application in my Drawer(side menu). What i eaxtly want is that when user click on logout he/she should get redirected to LOGIN screen . i have googled about this and got to know about two ways of doing it , but both the ways are not working for me , may be i am using them in wrong way. so i am here to seek your help .
The two methods are :-
1)
this.props
.navigation
.dispatch(NavigationActions.reset(
{
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'LoginScreen'})
]
}));
2) this.props.navigation.dispatch(NavigationActions.back());
this question may seems silly to you but i am really stuck at this point and just want to know how can i figure this out.Any help would be greatly Appreciated!!!!
Thanks in advance.
After trying almost everything, I've found the solution that worked for me:
this.props.navigation.popToTop(); // go to the top of the stack
this.props.navigation.goBack(null); // now show the root screen
Modal StackNavigator containing a Dismissable StackNavigator
Requires: react-navigation version: 1.0.0
Goal: Navigate from App TabNavigator to Screen 1 to Screen 2 to Screen N and then directly back to App TabNavigator.
Navigation hierarchy:
RootNavigator StackNavigator {mode: 'modal'}
App TabNavigator
TabA Screen
TabB Screen
TabC Screen
ModalScreen Screen
ModalStack DismissableStackNavigator
Screen 1 ModalStackScreen
Screen 2 ModalStackScreen
Screen N ModalStackScreen
Demo
package.json
{
"name": "HelloWorld",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"react": "16.0.0-alpha.6",
"react-native": "0.44.0",
"react-navigation": "^1.0.0"
},
"devDependencies": {
"babel-jest": "20.0.3",
"babel-preset-react-native": "1.9.2",
"jest": "20.0.3",
"react-test-renderer": "16.0.0-alpha.6"
},
"jest": {
"preset": "react-native"
}
}
index.ios.js (or index.android.js)
import React from 'react'
import {
AppRegistry,
Button,
Text,
View
} from 'react-native'
import {
StackNavigator,
TabNavigator
} from 'react-navigation'
class TabA extends React.Component {
state = {
startScreen: 'none',
returnScreen: 'none'
}
render () {
return (
<View style={{ padding: 40, paddingTop: 64 }}>
<Text style={{ fontSize: 20 }}>{this.constructor.name}</Text>
<Text>startScreen: {this.state.startScreen}</Text>
<Text>returnScreen: {this.state.returnScreen}</Text>
<Button
title="Open ModalScreen"
onPress={() => this.props.navigation.navigate('ModalScreen', {
startScreen: this.constructor.name,
setParentState: (state) => this.setState(state)
})}
/>
<Button
title="Open ModalStack"
onPress={() => this.props.navigation.navigate('ModalStack', {
startScreen: this.constructor.name,
setParentState: (state) => this.setState(state)
})}
/>
</View>
)
}
}
class TabB extends TabA {}
class TabC extends TabA {}
class ModalScreen extends React.Component {
render () {
const {
startScreen,
setParentState
} = this.props.navigation.state.params
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 20 }}>{this.constructor.name}</Text>
<Button
title="Close"
onPress={() => {
setParentState({
startScreen,
returnScreen: this.constructor.name
})
this.props.navigation.goBack()
}}
/>
</View>
)
}
}
const DismissableStackNavigator = (routes, options) => {
const StackNav = StackNavigator(routes, options)
return class DismissableStackNav extends React.Component {
static router = StackNav.router
render () {
const { state, goBack } = this.props.navigation
const screenProps = {
...this.props.screenProps,
dismissStackNav: () => goBack(state.key)
}
return (
<StackNav
screenProps={screenProps}
navigation={this.props.navigation}
/>
)
}
}
}
class ModalStackScreen extends React.Component {
render () {
const screenNumber = this.props.navigation.state.params && this.props.navigation.state.params.screenNumber || 0
const {
startScreen,
setParentState
} = this.props.navigation.state.params
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 20 }}>{this.constructor.name + screenNumber}</Text>
<View style={{
flexDirection: 'row',
justifyContent: 'space-between'
}}>
<Button
title={screenNumber === 0 ? "Close" : "Back"}
onPress={() => this.props.navigation.goBack(null)}
/>
<Button
title="Save"
onPress={() => {
setParentState({
startScreen,
returnScreen: this.constructor.name + screenNumber
})
this.props.screenProps.dismissStackNav()
}}
/>
<Button
title="Next"
onPress={() => this.props.navigation.navigate('ModalStackScreen', {
screenNumber: screenNumber + 1,
startScreen,
setParentState
})}
/>
</View>
</View>
)
}
}
const TabNav = TabNavigator(
{
TabA: {
screen: TabA
},
TabB: {
screen: TabB
},
TabC: {
screen: TabC
}
}
)
const ModalStack = DismissableStackNavigator(
{
ModalStackScreen: {
screen: ModalStackScreen
}
},
{
headerMode: 'none'
}
)
const RootStack = StackNavigator(
{
Main: {
screen: TabNav,
},
ModalScreen: {
screen: ModalScreen,
},
ModalStack: {
screen: ModalStack
}
},
{
mode: 'modal',
headerMode: 'none'
}
)
class App extends React.Component {
render () {
return <RootStack />
}
}
AppRegistry.registerComponent('HelloWorld', () => App)
Previous Answer
This solution is a sledgehammer. It causes the screen of the default tab in the TabNavigator to unmount and then mount again. If the Screen a tab launching the Modal with the StackNavigator passes some callbacks to update it's state, these callbacks will be called when the Screen is unmounted.
The solution was to add key: null to the reset object:
this.props.navigation.dispatch(NavigationActions.reset({
index: 0,
key: null,
actions: [
NavigationActions.navigate({ routeName: 'App'})
]
}))
I was tipped off by this comment.
(FYI - I got here via your comment asking for help.)
As per react navigation doc you can go to any stack by following ways:
check the following link for more details
React-navigation stack action link
1. import { StackActions, NavigationActions } from 'react-navigation';
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Profile' })],
});
this.props.navigation.dispatch(resetAction);
If you have a stack for profile then you can also go through like this check following link nested react navigation
import { NavigationActions } from 'react-navigation';
const navigateAction = NavigationActions.navigate({
routeName: 'Profile',
params: {},
action: NavigationActions.navigate({ routeName: 'SubProfileRoute' }),
});
this.props.navigation.dispatch(navigateAction);
(React Navigation 5.x) I had the problem of conditionally rendering the Screens like the example in
"https://reactnavigation.org/docs/en/auth-flow.html" As I understand, meant that the Stack navigators were not "rendered" and thus are not able to find each other. What I did was the below and in the logout page:
navigation.replace('SplashScreen')
My logic was: SplashScreen (Check for AsyncStorage Token),
if (token){
navigation.navigate('App')
}else{
navigation.navigate('StartScreen')
}
In StartScreen, just navigate to Signin or Register where you go back to App if login is successful.
As a reference,
function AppBottomNavigator(){
return(
<AppNavigator.Navigator
initialRouteName={'Home'} ...}>
<AppNavigator.Screen name='A' component={ScreenA}/>
<AppNavigator.Screen name='B' component={ScreenB}/>
<AppNavigator.Screen name='C' component={ScreenC}/>
<AppNavigator.Screen name='D' component={ScreenD}/>
<AppNavigator.Screen name='E' component={ScreenE}/>
</AppNavigator.Navigator>
)
}
export default App stuff...
...return(
<AuthContext.Provider value={authContext}>
<NavigationContainer>
<AuthStack.Navigator screenOptions={{headerShown:false}}>
<>
<AuthStack.Screen name='SplashScreen' component={SplashScreen}/>
<AuthStack.Screen name='StartScreen' component={StartScreen} />
<AuthStack.Screen name='SignIn' component={SignIn} />
<AuthStack.Screen name='Register' component={Register} />
<AuthStack.Screen name='App' component={AppBottomNavigator}/>
</>
</AuthStack.Navigator>
</NavigationContainer>
</AuthContext.Provider>
)
I am also quite new to this but it worked so if someone else has a safer/tidier/general solution, I would quite like to know, too.

ListItem onPress not working as it should

I'm using React Native and react-native-elements to render a list of options in a side menu, however when I run the project, the onPress prop in ListItem fails to act as it should. The three console logs seem to iterate automatically with the main content on the screen when run, but when the side menu is opened the list items cannot be pressed and nothing further is logged in the console. Is there something wrong with my onPress function?
import { SideMenu, List, ListItem } from 'react-native-elements';
import React, { Component } from 'react';
import { View, StyleSheet } from 'react-native';
import { MaterialIcons } from '#expo/vector-icons';
export default class Home extends Component {
state = {
toggled: false,
}
toggleSideMenu () {
this.setState({
toggled: !this.state.toggled
})L
render() {
const list = [
{
name: 'Profile',
pic: 'assignment-ind',
//nav: this.props.navigation.navigate('Profile', { user: this.state.user })
nav: console.log('pressing Profile!'),
},
{
name: 'Settings',
pic: 'settings-applications',
nav: console.log('pressing Settings!'),
},
{
name: 'Logout',
//nav: firebase.auth().signOut() // sign user out
nav: console.log('pressing Logout!'),
}
]
const MenuComponent = (
<View style={{flex: 1, backgroundColor: 'white', paddingTop: 10}}>
<List containerStyle={{marginBottom: 20}}>
{
list.map((item, i) => (
<ListItem
onPress={() => item.nav}
leftIcon={{ name: item.pic }}
key={i}
title={item.name}
/>
))
}
</List>
</View>
);
return (
<SideMenu
menu={MenuComponent}
toggled={this.state.toggled}>
<View style={styles.container}>
<View style={{ flexDirection: 'row' }}>
<TouchableHighlight
style={{marginTop: 20, marginLeft: 9}}
onPress={this.toggleSideMenu.bind(this)}
underlayColor='transparent'>
<MaterialIcons
color='white'
name='menu'
size={28}
/>
</TouchableHighlight>
</View>
</View>
</SideMenu>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'black',
},
});
Figured it out:
I made each proper methods within the list object:
const list = [
{
name: 'Profile',
pic: 'assignment-ind',
//nav: this.props.navigation.navigate('Profile', { user: this.state.user })
nav: () => { console.log('pressing Profile!'); },
},
{
name: 'Settings',
pic: 'settings-applications',
nav: () => { console.log('pressing Settings!'); },
},
{
name: 'Logout',
//nav: firebase.auth().signOut() // sign user out
nav: () => { console.log('pressing Logout!'); },
}
Then I added parentheses to the onPress function:
onPress={() => item.nav()}
onPress has to be a method. You need to make nav of the list a method by binding it there itself. For eg.
nav : () => {console.log("Logout pressed")}
Also you need to call it from onPress.
onPress : item.nav() // Note the brackets.
Happy coding.

Categories

Resources