User to DB code example

Let's see the code for adding a user to your database after they sign in.

Now that you've read the high-level explanation of adding a user to the database, let's see some code.

If you want to skip up to the code, you can see the example on Github. You can also scroll down to "Add user exists in DB logic."

Make sure you've already completed the setup guide, installation & have deployed your app before continuing.

TLDR

  1. Add a userExistsInDb state variable.

  2. Add onAuthStateChanged prop to DoormanProvider. This function gets called whenever the user signs in or out.

    1. Inside this function, call your DB to see if user exists already, and if not, send to the onboarding flow.

    2. Call setUserExistsInDb to update the state based on the DB's response.

  3. When userExistsInDb is false, render an Onboarding screen that lets users enter information, and then adds them to the database. This goes inside of AuthGate.

    1. Call setUserExistsInDb(true) when a user is successfully added to the DB from the Onboarding screen to update the state.

File overview

We're going to create 3 files. AuthLogic and Onboarding contain code distinct to this tutorial.

  • App.tsx initialize Firebase, render app

  • AuthLogic.tsx initialize Doorman, and conditionally render an authentication flow, an onboarding screen, or an authenticated app.

  • Onboarding.tsx Collect user information if they aren't in the DB yet.

1. Initialize Firebase in App

App.tsx

import AuthLogic from './AuthLogic'

import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/firestore' // <- if you use Firestore

if (!firebase.apps.length) {
  // you can replace this with your firebase config
  firebase.initializeApp({
    apiKey: 'AIzaSyCn8HyP1tVZiagk-YvZRwjSwKdwQw5Pvng',
    authDomain: 'tester-9d8bb.firebaseapp.com',
    databaseURL: 'https://tester-9d8bb.firebaseio.com',
    projectId: 'tester-9d8bb',
    storageBucket: 'tester-9d8bb.appspot.com',
    messagingSenderId: '760778283392',
    appId: '1:760778283392:web:05cb35d0837c93c6584965',
  })
}

export default AuthLogic

This is simple boilerplate code that is no different than normal initialization for Firebase/Doorman.

You can replace the firebase.initializeApp config variable with your own firebase config.

2. Initialize Doorman in AuthLogic

This tutorial will rely on the DoormanProvider implementation instead of withPhoneAuth. (They both achieve the same thing, as mentioned in the quick example.)

First, create a component called AuthLogic.

AuthLogic.tsx

import React from 'react'

const AuthLogic = () => {
  return <></>
}

export default AuthLogic

Next, we'll add the Doorman Provider. This provider must wrap your entire app at the root file.

import React from 'react'
import { DoormanProvider } from 'react-native-doorman'

const AuthLogic = () => {
  return (
    <DoormanProvider publicProjectId="djzlPQFxxzJikNQgLwxN">
      {/* Our auth logic will go here next. */}
    </DoormanProvider>
  )
}

export default AuthLogic

You can replace the publicProjectId field with your own. How do I find my public Project Id?

2.1 Add AuthGate component

The AuthGate updates the state based on whether or not the user is authenticated.

import React from 'react'
import { DoormanProvider, AuthGate } from 'react-native-doorman'

const AuthLogic = () => {
  return (
    <DoormanProvider publicProjectId="djzlPQFxxzJikNQgLwxN">
      <AuthGate></AuthGate>
    </DoormanProvider>
  )
}

export default AuthLogic

AuthGate accepts a single child: a function that returns a component. It receives the user and loading fields as arguments.

<AuthGate>
  {({ user, loading }) => {
    // if loading auth listener
    if (loading) return <></>
    
    // if user is not authenticated
    if (!user) return <AuthFlow />
    
    // your actual app component, which appears after
    // the user has authenticated
    return <AfterAuth />
  }}
</AuthGate>

Whoa, where did AuthFlow come from? That's the Doorman component that lets your users sign in with phone number. AfterAuth is your normal app component.

Our file now looks like this:

AuthLogic.tsx (or .js if you don't use TypeScript)

import React from 'react'
import { DoormanProvider, AuthGate, AuthFlow } from 'react-native-doorman'

const AuthLogic = () => {
  return (
    <DoormanProvider publicProjectId="djzlPQFxxzJikNQgLwxN">
      <AuthGate>
        {({ user, loading }) => {
          // if loading auth listener
          if (loading) return <></>
          
          // if user is not authenticated
          if (!user) return <AuthFlow />
          
          // your actual app component, which appears after
          // the user has authenticated
          return <AfterAuth />
        }}
      </AuthGate>
    </DoormanProvider>
  )
}

export default AuthLogic

2.2 Add user exists in DB logic

Now, on to the code that lets you add your user to the DB.

First, let's add a userExistsInDb state variable, whose initial value is false. Add a checkingIfUserExists state variable too, which indicates if the DB check is loading or not.

const AuthLogic = () => {
  const [userExistsInDb, setUserExistsInDb] = useState(false)
  const [checkingIfUserExists, setCheckingIfUserExists] = useState(false)

  // render code here
}

Next, add a listener callback to the DoormanProvider component using its onAuthStateChanged prop.

const AuthLogic = () => {
  const [userExistsInDb, setUserExistsInDb] = useState(false)
  const [checkingIfUserExists, setCheckingIfUserExists] = useState(false)
  
  const onAuthStateChanged = async (user) => {
    if (user) {
      const { uid }  = user
      
      setCheckingIfUserExists(true)
      
      // user your own function here that calls your database to check
      const exists = await checkIfUserExistsInDb(uid)
      
      // if you're using Firestore, it might look like this:
      const { exists } = await db.doc(`users/${uid}`).get()
      
      // update the state based on our DB value
      setUserExistsInDb(exists)
      setCheckingIfUserExists(false)
    } else {
      // user is not signed in, reset the state to false
      setUserExists(false)
      setCheckingIfUserExists(false)
    }  
  }
  
  return (
    <DoormanProvider 
      publicProjectId="djzlPQFxxzJikNQgLwxN"
      onAuthStateChanged={onAuthStateChanged}
    >
      ...
    </DoormanProvider>
  )
}

The onAuthStateChanged prop is a function that gets called whenever the user signs in or out. It follows the same API from firebase.

2.3 Render Onboarding

The final step is to render an Onboarding screen if userExistsInDb is false.

// 👇 We'll create this in the final step 
// you can import your own, too!
import Onboarding from './Onboarding'

...

<AuthGate>
  {({ user, loading }) => {
    // add checkingIfUserExists to loading condition
    if (loading || checkingIfUserExists) return <></>
    
    if (!user) return <AuthFlow />
    
    // If user is authenticated, but doesn't exist in the DB,
    // render the onboarding flow.
    // We pass it a callback function called onUserAddedToDb
    // this function will set userExistsInDb to true
    // it gets called after the DB has been updated by <Onboarding />
    if (!userExistsInDb) {
      return (
        <Onboarding 
          onUserAddedToDb={() => setUserExistsInDb(true)} 
        />
      )
    }
    
    // your actual app component, which appears after
    // the user has authenticated
    return <AfterAuth />
  }}
</AuthGate>

🎉That's it! All that's left is to make the Onboarding screen.

Here is our final AuthLogic screen, in its entirety:

import React, { useState } from 'react'
import { DoormanProvider, AuthGate, AuthFlow } from 'react-native-doorman'
import Onboarding from './Onboarding'
import AfterAuth from './AfterAuth'
import { db } from './db'

const AuthLogic = () => {
  const [userExistsInDb, setUserExistsInDb] = useState(false)
  const [checkingIfUserExists, setCheckingIfUserExists] = useState(false)

  return (
    <DoormanProvider
      onAuthStateChanged={async user => {
        if (user) {
          const { uid } = user

          setCheckingIfUserExists(true)

          // 👇 user your own function here that calls your database to check
          // const exists = await checkIfUserExistsInDb(uid)

          // if you're using Firestore, it might look like this:
          const { exists } = await db.doc(`users/${uid}`).get()

          // update the state based on our DB value
          setUserExistsInDb(exists)
          setCheckingIfUserExists(false)
        } else {
          // user is not signed in, reset the state to false
          setUserExistsInDb(false)
          setCheckingIfUserExists(false)
        }
      }}
      publicProjectId="djzlPQFxxzJikNQgLwxN"
    >
      <AuthGate>
        {({ user, loading }) => {
          // add checkingIfUserExists to loading condition
          if (loading || checkingIfUserExists) return <></>

          if (!user) return <AuthFlow />

          // If user is authenticated, but doesn't exist in the DB,
          // render the onboarding flow.
          // We pass it a callback function called onUserAddedToDb
          // this function will set userExistsInDb to true
          // it gets called after the DB has been updated by <Onboarding />
          if (!userExistsInDb) {
            return (
              <Onboarding onUserAddedToDb={() => setUserExistsInDb(true)} />
            )
          }

          // your actual app component, which appears after
          // the user has authenticated
          return <AfterAuth />
        }}
      </AuthGate>
    </DoormanProvider>
  )
}

export default AuthLogic

Note: If you have your own Onboarding screen (or React Navigation stack, you can render it in place of Onboarding.

  • If you're using a React Navigation Stack in place of Onboarding (assuming it's with v5), then pass the onUserAddedToDb function as a param to your stack, and call it from your screen using useRoute().params.onUserAddedToDb.

3. Create <Onboarding /> screen

👋Don't forget to call the onUserAddedToDb function after successfully adding your user to the database, as seen in line 19 below! If you don't call it, the app won't re-render.

Here's an example of a basic Onboarding screen:

Onboarding.tsx

import React, { useState }  from 'react'
import { TextInput, Button, View } from 'react-native'
import { useDoormanUser } from 'react-native-doorman'

const Onboarding = ({ onUserAddedToDb }) => {
  const [name, setName] = useState('')
  const { uid } = useDoormanUser()
  
  const handleSubmit = async () => {
    // Implement your own DB function here
    await addUserToDb({ uid, name })
    
    // ...if you're using Firestore, it might look like:
    await db.doc(`users/${uid}`).set({ name }, { merge: true })
    
    // Finally, once the user has been added, 
    // call the callback function from the props.
    // 🚨if you forget to call this function, the app won't re-render
    onUserAddedToDb()
  }
  
  return (
    <View style={styles.container}>
      <TextInput  
        placeholder="Enter your name"
        value={name}
        onChangeText={setName}
      />
      <Button
        title="Submit name"
        onPress={handleSubmit}
      />
    </View>
  )
}

export default Onboarding

const styles= StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center'
  }
})

4. (Bonus) Create <AfterAuth />

Here's an example app screen, which you can make in your AfterAuth.tsx file:

import React from 'react'
import {
  Page,
  ScreenBackground,
  useDoormanUser,
  H1,
  Paragraph,
} from 'react-native-doorman'
import { Button } from 'react-native'

const AfterAuth = () => {
  const { uid, signOut } = useDoormanUser()
  return (
    <Page
      style={{ marginTop: 100, alignItems: 'center' }}
      background={() => <ScreenBackground />}
    >
      <H1 style={{ color: 'white' }}>Welcome to Doorman.</H1>
      <Paragraph style={{ color: 'white' }}>
        Sign out below, if {`you'd`} like. Your user id is {uid}.
      </Paragraph>
      <Button title="Sign Out" color="white" onPress={signOut} />
    </Page>
  )
}

export default AfterAuth

5. If you're using Firestore

If you're using Firestore as your DB, you'll find examples in this tutorial for how to read and write a user.

For the sake of the tutorial, you can create a db.ts file, and populate it with this. You can also set a custom firebaseConfig from your own Firebase project.

import firebase from 'firebase/app'

export const firebaseConfig = {
  apiKey: 'AIzaSyCn8HyP1tVZiagk-YvZRwjSwKdwQw5Pvng',
  authDomain: 'tester-9d8bb.firebaseapp.com',
  databaseURL: 'https://tester-9d8bb.firebaseio.com',
  projectId: 'tester-9d8bb',
  storageBucket: 'tester-9d8bb.appspot.com',
  messagingSenderId: '760778283392',
  appId: '1:760778283392:web:05cb35d0837c93c6584965',
}

export const db = !firebase.apps.length
  ? firebase.initializeApp(firebaseConfig).firestore()
  : firebase.app().firestore()

Last updated