skip to Main Content

I am using React navigation v6 for my react native application. I am stuck at trying to detect if the app is launched for the first time by the user or not.

I have tried to set FIRST_LAUNCH through AsyncStorage and then depending on its value I set the initialRouteName in the Stack.Navigator. This doesn’t seem to work as I came to know that createNativeStackNavigator is synchronous doesn’t wait for the getItem‘s promise to be fulfilled or rejected to finish up being executed.

App.js

const App = () => {
    useEffect(() => {
        SplashScreen.hide();
    },[]);
    return (
        <View style={styles.container}>
            <Routes />
        </View>
    );
};

Routes.js

const Stack = createNativeStackNavigator();

function Routes(){
    const [firstLaunch , setFirstLaunch] = useState(true);
    
    const checkFirstLaunch = () => {
        AsyncStorage.getItem('FIRST_LAUNCH').then(value => {
            if(value === null){
                AsyncStorage.setItem('FIRST_LAUNCH', 'false');
            }
            setFirstLaunch(false);
        })
    }

    useEffect(() => {
        checkFirstLaunch();
        
    }, [])

    return(
        <NavigationContainer>
                <Stack.Navigator
                    screenOptions={{
                        headerShown: false
                    }}
                    initialRouteName={firstLaunch ? 'Onboarding' : 'TenantHome'}
                >
                    <Stack.Screen name="Onboarding" component={OnboardingRoutes} />
                    <Stack.Screen name="TenantHome" component={TenantRoutes} />
                </Stack.Navigator>
        </NavigationContainer>
    )
}

export default Routes;

This doesn’t seem to work and firstLaunch is always true.

I have also read a solution where someone suggested to make a splash screen of my own which is the default first screen and use that to navigate to the onboarding or tenant home screen accordingly. But I already have a splash screen set up by LaunchScreen.xib and hiding it using SplashScreen.hide() in App.js. Also I don’t know if manually creating it is good practice or not.

Can someone help me get about this?

2

Answers


  1. Maybe you should try async/await like this:

    const controlStorage = async () => {
      if (await !AsyncStorage.getItem("FIRST_LAUNCH")) {
        AsyncStorage.setItem('FIRST_LAUNCH', 'false');
      }
      setFirstLaunch(false);
    }
    

    Or:

    const controlStorage = async () => {
      await AsyncStorage.getItem("FIRST_LAUNCH")) ? setFirstLaunch(false); : AsyncStorage.setItem('FIRST_LAUNCH', 'false'); setFirstLaunch(false);
    }
    

    And async storage work not like localStorage. that’s why sometimes a little bit we get confused. We get different data from asyncstorage

    Login or Signup to reply.
  2. If you want to use AsyncStorage, then the below code should work fine:

    const checkFirstLaunch = async () => {
        const __first_launch = await AsyncStorage.getItem('FIRST_LAUNCH');
        if (!__first_launch) {//This means that no key found with name 'FIRST_LAUNCH' which indicates that the app is launched for the first time
            AsyncStorage.setItem('FIRST_LAUNCH', "Done");//Instead of false try setting value to something like "Done"
            setFirstLaunch(true);//This line is unneccesary as you are setting the default value to true
        } else {//This means that that app is not launched for the first time so we can set setFirstLaunch to false
            setFirstLaunch(false);
        }
    }
    

    If the above code still does not work, then you can try using react-native-sqlite-storage. I know it will increase the complexity of the code but it is much faster than the AsyncStorage, so it will also improve the performance of your app.

    Check the below code for your reference:

    import { openDatabase } from 'react-native-sqlite-storage';
    var db = openDatabase({ name: 'YOURAPPDB.db' });
    
    useEffect(() => {
        CreateFirstLaunchTable();//Always remember to create the table first before accessing it
        CheckFirstLaunch();//Checking First Launch in local db
    }, []);
    
    const CreateFirstLaunchTable = () => {
        try {
            db.transaction(tx => {
                tx.executeSql(
                    'CREATE TABLE IF NOT EXISTS FirstLaunch (ID INTEGER PRIMARY KEY AUTOINCREMENT, IsFirstLaunch TEXT)'
                    , null, (txObj, resultSet) => {
                        console.log('CreateFirstLaunchTable', resultSet);
                    }, (txObj, error) => {
                        console.log('FirstLaunch Table Creation Error : ', txObj.message);
                    }
                );
            })
        }
        catch (ex) {
            console.log('Table Creation Error: ' + ex);
        }
    }
    
    const InsertDataIntoFirstLaunch = () => {
        try {
            db.transaction(tx => {
                tx.executeSql("INSERT INTO FirstLaunch (IsFirstLaunch) values ('Done')", null,
                    (txObj, resultSet) => {
                        if (resultSet.rowsAffected == '1') {
                            console.log('Data inserted successfully');
                        }
                        else {
                            console.log('No Data Insert or updated : ', JSON.stringify(txObj), JSON.stringify(resultSet));
                        }
                    },
                    (txObj, error) => {
                        console.log('Data Insert/Update Error : ', txObj.message);
                    }
                )
            })
        }
        catch (e) {
            console.log(e);
        }
    }
    
    const CheckFirstLaunch = () => {
        try {
            db.transaction(function (txn) {
                txn.executeSql(
                    "SELECT * FROM FirstLaunch", null,
                    (txObj, resultSet) => {
                        if (resultSet.rows.length == 0) {//It means there is no data in the table which indicates that the app is launched for the first time
                            setFirstLaunch(true);
                        }
                        else {//resultSet.rows.length will always be 1 after 2nd and subsequent launches
                            setFirstLaunch(false);
                            InsertDataIntoFirstLaunch();//Inserting into local db
                        }
                    },
                    (txObj, error) => {
                        console.log('Getting table details error : ', txObj.message);
                    }
                );
            });
        }
        catch (e) {
            console.log(e);
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search