How to detect application first launch in react native app? - javascript

In my scenario, I am having three different screens like Page1, Page2, Page3. Here, if the user last visited page 2 then next time if user open application, instead of showing page1 need to show page2. How to achieve this using a react-native application?
I tried by using async storage but don’t know how to manage multiple pages
AsyncStorage.getItem("alreadyLaunched").then(value => {
if(value == null){
AsyncStorage.setItem('alreadyLaunched', true); // No need to wait for `setItem` to finish, although you might want to handle errors
this.setState({firstLaunch: true});
}
else{
this.setState({firstLaunch: false});
}}) // Add some error handling, also you can simply do this.setState({fistLaunch: value == null})
App.js
import { createAppContainer } from 'react-navigation';
import { createStackNavigator} from 'react-navigation-stack';
import FirstPage from './pages/FirstPage';
import SecondPage from './pages/SecondPage';
import ThirdPage from './pages/ThirdPage';
//import all the screens we are going to switch
const App = createStackNavigator({
//Constant which holds all the screens like index of any book
FirstPage: { screen: FirstPage, header: null},
SecondPage: { screen: SecondPage, headerLeft: null, headerBackTitle: null},
ThirdPage: { screen: ThirdPage},
},
{
initialRouteName: 'FirstPage',
}
);
export default createAppContainer(App);

You should use AsyncStorage to store the current screen, so any time you move from a screen to another you should call
AsyncStorage.setItem('screen', 'nameOfYourScreen')
and in App.js you should call
AsyncStorage.getItem('screen');
and affect it to initialRouteName
PS: getItem() is asynchronous.

Create another page say "Decider.js" and also import createSwitchNavigator from react-navigation. and make it your default page every time app launches. and there we will check where was the user last time and navigate to that page.
Let achieve this as below:
App.js
import { createSwitchNavigator, createAppContainer } from 'react-navigation'; //new import createSwitchNavigator
import { createStackNavigator} from 'react-navigation-stack';
import FirstPage from './pages/FirstPage';
import SecondPage from './pages/SecondPage';
import ThirdPage from './pages/ThirdPage';
import Deccider from './pages/Decider.js'; // New deciding screen
//import all the screens we are going to switch
const App = createStackNavigator({
//Constant which holds all the screens like index of any book
FirstPage: { screen: FirstPage, header: null},
SecondPage: { screen: SecondPage, headerLeft: null, headerBackTitle: null},
ThirdPage: { screen: ThirdPage},
},
{
initialRouteName: 'FirstPage',
}
);
export default createAppContainer(createSwitchNavigator(
{
AuthLoading: Decider,
App: App,
},
{
initialRouteName: 'AuthLoading',
}
));
Now on every app launch first screen called will be Decider.js
Decide.js
import React from 'react';
import {
AsyncStorage,
View,
} from 'react-native';
export default class AuthLoadingScreen extends React.Component {
constructor() {
super();
this._bootstrapAsync();
}
_bootstrapAsync = async () => {
var alreadyLaunchedPage = await
AsyncStorage.getItem('alreadyLaunchedPage');
if (alreadyLaunchedPage) {
this.props.navigation.navigate(alreadyLaunchedPage);
} else {
this.props.navigation.navigate('App');
}
};
render() {
return (
<View style={{ flex: 1 }}>
{/* Any Loading or splash design */}
</View>
);
}
}
**On every page's (FirstPage,SecondPage,ThirdPage) componentDidMount **
...
componentDidMount(){
AsyncStorage.setItem("alreadyLaunchedPage","FirstPage")//if FirstPage
// AsyncStorage.setItem("alreadyLaunchedPage","SecondPage")//if SecondPage
// AsyncStorage.setItem("alreadyLaunchedPage","ThirdPage")//if ThirdPage
}
...
Hope it will solve your problem.
NOTE: Here we have used createSwitchNavigator to prevent going back to Decider.js once you reach any of the FirstPage, SecondPage or ThirdPage.

Related

How to solve "Can't find variable: App" in React Native?

I am new to React Native and I don't understand how to solve this problem. I already installed react-native-gesture-handler.
I am getting this error in the command:
Accessing view manager configs directly off UIManager via UIManager['getConstants'] is no longer supported. Use UIManager.getViewManagerConfig('getConstants') instead.
This is a part of the code:
import { createAppContainer, DrawerNavigator } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import Home from "./src/screens/Home.js";
import first from "./src/screens/first.js";
import React from 'react';
class App extends React.Component{
render(){
return(
<RootStack/>
)
}
}
const RootStack = createStackNavigator ({
Home:{screen:Home,
navigationOptions: {
header: null
}},
first:{screen:first,
navigationOptions: {
header: null
}}
});
//const App = createAppContainer(RootStack);
export default App;
I think this way is better:
const AppNavigator = createSwitchNavigator({
Auth: {
screen: Auth
},
Root: {
screen: BottomTabNavigator
}
})
const AppContainer = createAppContainer(AppNavigator)
const App = () => {
return (
<AppContainer />
)
}
export default App
OR
if it didn't work then you better check your index.js file whether you imported App Component (Root component) correctly or not?

How to navigate to a page in react native that is not in the tab navigator?

I have this in my react-native code:
const MainNavigator = createBottomTabNavigator({
Home: Home,
"Exercise List": ExerciseList,
Exercise: Exercise,
"Current Workout": CurrentWorkout,
})
but I only want to navigate to the Exercise tab when I click to it via the exerciseList page like so:
onPress={() => navigate("Exercise", { name: item.name })}
and I don't want it to appear in the navigation bar at the bottom. But if I remove it from MainNavigator above then it doesn't work when I click the onPress above. Is there a way to Navigate to the component without it being in the tab nav?
You need to make some change in app.js. add createBottomTabNavigator inside createStackNavigator. Add those component into stacknavigator in which you do not want to add into bottom tab navigator. In createBottomTabNavigator add those component which you want to show in tab bar
Please check following code
import React, { Component } from "react";
import {
Platform,
StyleSheet,
Text,
View,
SafeAreaView,
ScrollView,
Dimensions
} from "react-native";
import { createStackNavigator, createBottomTabNavigator } from "react-navigation";
import LoginScreen from "./Screens/LoginScreen";
export default class App extends Component {
render() {
return <StackNav />;
}
}
const StackNav = createStackNavigator(
{
TabNavigator: {
screen: AppTabNavigator,
navigationOptions: {
headerMode: "none",
header: null
}
},
First: {
screen: First,
navigationOptions: {
headerMode: "none",
header: null
}
},
Second: {
screen: Second,
navigationOptions: {
headerMode: "none",
header: null
}
}
},
{
initialRouteName: "TabNavigator"
}
);
const AppTabNavigator = createBottomTabNavigator({
Login: {
screen: LoginScreen
}
});
Add it with createSwitchNavigator. A working example is given below
const Navigation = createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
Qr: QrPage,
},
{
initialRouteName: 'AuthLoading',
}
Here I can access to my Qr page from any where.
here is two method of of call other components which doesn't contains in tabNavigator:
const otherAppNavigator = createStackNavigator({//all of this are not in TabNavigator
dashboard: {
screen: Dashboard,
},
userProfile: {
screen: UserProfile
},
onGoingPickup: {
screen: OnGoingPickup
},
});
const TabNavigator = createBottomTabNavigator({
home: otherAppNavigator,//<<<<<<<<<<
about:foo,
}
)
const MainNavigator = createSwitchNavigator({
firstPage: {//it's not in TabNavigator<<<<<<<<<<<<<<<<<<<<<<<<<<
screen: Login,
},
verification: {//its not in TabNavigator<<<<<<<<<<<<<<<<<<<<<<<<
screen: verification
},
dashboard: {
screen: TabNavigator
}
})
export default createAppContainer(MainNavigator); //the main navigator is which you bind in here
pay attention to the last line ....!!!!
hope to be helpful.

undefined is not a function (evaluating'_reactNavigation.NavigationActions.reset')

I want to navigate a splash screen to next screen after certain timeout. Splash screen have an animation, done with the help of Airbnb Lottie for React Native.
The splashscreen code goes as follows:
import React from "react";
import { Animated, Easing } from "react-native";
import LottieView from "lottie-react-native";
import { NavigationActions } from "react-navigation";
export default class SplashScreen extends React.Component {
static navigationOptions = {
header: null
};
constructor() {
super();
this.state = {
progress: new Animated.Value(0),
}
}
componentDidMount() {
setTimeout(() => {
this.navigateToWalkthrough()
}, 3500);
Animated.timing(this.state.progress, {
toValue: 1,
duration: 3000,
easing: Easing.linear,
}).start();
}
navigateToWalkthrough = () => {
const navigateAction = NavigationActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: "Walkthrough" })],
});
this.props.navigation.dispatch(navigateAction);
}
render() {
return(
<LottieView
source={require("../assets/splash/SplashScreenAnimation.json")}
progress={this.state.progress}
/>
);
}
}
After I run the app following errors comes up:
undefined is not a function (evaluating'_reactNavigation.NavigationActions.reset')
The Main.js file looks like as follows:
import React from "react";
import { View, Text } from "react-native";
import { createStackNavigator } from "react-navigation";
import SplashScreen from "./screens/SplashScreen";
import Walkthrough from "./screens/Walkthrough";
const Routes = createStackNavigator({
Home: {
screen: SplashScreen
},
Walkthrough: {
screen: Walkthrough
}
});
export default class Main extends React.Component {
render() {
return <Routes />;
}
}
Any help/feedback?
reset action is removed from NavigationActions and there is StackActions specific to StackNavigator in v2 of react-navigation.
StackActions is an object containing methods for generating actions
specific to stack-based navigators. Its methods expand upon the
actions available in NavigationActions.
The following actions are supported:
Reset - Replace current state with a new state
Replace - Replace a route at a given key with another route
Push - Add a route on the top of the stack, and navigate forward to it
Pop - Navigate back to previous routes
PopToTop - Navigate to the top route of the stack, dismissing all other routes
import { StackActions, NavigationActions } from 'react-navigation';
navigateToWalkthrough = () => {
const navigateAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: "Walkthrough" })],
});
this.props.navigation.dispatch(navigateAction);
}

React Native navigation - undefined is not an object

I'm new to React native and trying to follow tutorials to learn however can't get navigation between screens to work. I have previously got it working fine with one screen but when adding navigation I get errors.
Following this: https://facebook.github.io/react-native/releases/next/docs/navigation.html
Gives me code like this:
import React from 'react';
import {
StackNavigator,
} from 'react-navigation';
export default class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<Button
title="Go to Jane's profile"
onPress={() =>
navigate('Profile', { name: 'Jane' })
}
/>
);
}
}
class ProfileScreen extends React.Component {
static navigationOptions = {
title: 'Profile',
};
render() {
return (
<Button title="do nothing"/>
);
}
}
const App = StackNavigator({
Home: { screen: HomeScreen },
Profile: { screen: ProfileScreen },
});
Trying to run this (through the expo app) results in the error
undefined is not an object (evaluating 'this.props.navigation.navigate')
So am I doing navigation correctly and how do I fix this error?
You need to use AppRegistry.registerComponent in your App.
A nice way of doing this is to create a src directory and then create the 2 js files, HomeScreen and ProfileScreen there. Then create and App.js on the same level as your index.android.js or index.ios.js and include these 2 files and declare the StackNavigator as you did in your code, but instead of const App you need to have const NameOfYourApp, where NameOfYourApp is how you named your project when you ran create-react-native-app.(If it is App, just leave it like that)
Then you need to add this line at the end, AppRegistry.registerComponent('NameOfYourApp', () => NameOfYourApp);
import React from 'react';
import {
StackNavigator,
} from 'react-navigation';
import HomeScreen from './src/HomeScreen'
import ProfileScreen from './src/ProfileScreen'
const NameOfYourApp = StackNavigator({
Home: { screen: HomeScreen },
Profile: { screen: ProfileScreen },
});
AppRegistry.registerComponent('NameOfYourApp', () => NameOfYourApp)
The final step is to import your App.js file in your index.android.js or index.ios.js
import './App';

Reuse screen in React Navigation

I'm new to React Native and trying to set up a navigation between two screens (or pages) using react-navigation package. I'm using a StackNavigator right now.
The problem I am facing is that there seems to be no way to navigate back to a previous screen. All I can do is call navigate(). If, for example, I want to navigate from Home to FRW and back to Home, it seems this will leave me with two instances of Home on the stack that are executed in parallel (one of which can't be seen). My code is something like this:
app.js
import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import { StackNavigator } from 'react-navigation';
import HomeScreen from './views/HomeScreen.js'
import FRWScreen from './views/FRWScreen.js'
const MainNavigator = StackNavigator({
FRW: { screen: FRWScreen },
Home: { screen: HomeScreen },
}, {
headerMode: 'screen',
headerVisible: false,
navigationOptions: {
header: null
},
initialRouteName: "Home"
});
export default class TestApp extends Component {
render() {
return (
<MainNavigator></MainNavigator>
);
}
}
AppRegistry.registerComponent('TestApp', () => TestApp);
HomeScreen.js
export default class HomeScreen extends Component {
static navigationOptions = {
title: 'Welcome'
};
(...)
onSomeButtonPressed() {
this.props.navigation.navigate('FRW');
}
componentDidMount() {
if (this.locationWatchID !== undefined) return;
this.locationWatchID = navigator.geolocation.watchPosition((position) => {
console.log(this.locationWatchID);
});
}
componentWillUnmount() {
navigator.geolocation.clearWatch(this.locationWatchID);
}
render() {
(...)
return (
<View style={styles.container}>
<MapView ref={ref => { this.map = ref; }} />
<TouchableHighlight
style={styles.someButton}
onPress={this.onSomeButtonPressed.bind(this)}
>
<Text>Press Me</Text>
</TouchableHighlight>
</View>
)
}
}
FRWScreen.js looks similar to HomeScreen.js (and contains .navigate("Home"))
The result of this code is, after navigating to FRW and back, that the geolocation callback is executed twice with different watchIDs. Which makes me believe the HomeScreen is actually on the navigation stack twice.
On your FRWScreen you should use this.props.navigation.goBack(null) instead. See https://reactnavigation.org/docs/navigators/navigation-prop#goBack-Close-the-active-screen-and-move-back.

Categories