Tutorial: https://www.youtube.com/watch?v=bxKbv1KZVkI\&list=PLJeCS8DwkVT_NQpBCd0KMZMc60vUQzw-Q\&index=3

**1 - Setting Up Expo for TikTok Clone with React NativeStep-by-Step Guide**

2 - Adding Native Wind and Expo Router for TikTok Clone with React Native

  • Start by running the commands in step 1: https://www.nativewind.dev/docs/getting-started/installation
  • Run npx tailwindcss init to create a tailwind.config.js file
  • content: [”./app/**/*.{js,jsx,ts,tsx}”, “./components/**/*.{js,jsx,ts,tsx}”],
    • This line in tailwind.config.js tells tailwind to style all js, jsa, ts, and tsx files in both the app and components folder.
  • Follow the steps in the docs instead of the video for this part.
  • Add metro.config.js to expo: https://docs.expo.dev/guides/customizing-metro/
  • Continue watching from here: https://youtu.be/bxKbv1KZVkI?si=mKoY4ahd-_OXGJoQ\&t=178
  • Add a className property to the View and Text components: https://www.nativewind.dev/docs/getting-started/installation#try-it-out
  • ***Note: Could not get the global.css to import without using the exact path, there should be a fix to this.
  • **Note: If you add another folder that has view components in it, you will have to add it to tailwind.config.js.
  • Add some new tabs to (tabs)/_layout.tsx:
    • In this order Home (default), Friends, Camera, Inbox, Profile
  • Create the files needed for the new tabs:
    • In this order friends.tsx, camera.tsx, inbox.tsx, profile.tsx
  • Copy the contents of HomeScreen into each file:
    • (Remove HomeScreen before function).
  • Add a new navigator: https://docs.expo.dev/tutorial/add-navigation/
    • ***Note:We’re going to do authentication because when we first open the app we want to force the user to log in or sign up, then they get to the home page.
  • Create a new (auth) subfolder in the app folder.
  • Create the required _layout.tsx and index.tsx files and a signup.tsx file.
  • Copy the same HomeScreen content from inbox.tsx as before:
    • See photo under “Copy the contents of HomeScreen into each file:”
  • In (auth)/_layout.tsx declare a new navigator; copy _layout.tsx into (auth)/_layout.tsx.
    • ***Note:We don’t want another Tab navigator, this time we need a Stack.Screen navigator.
  • Within (auth)/_layout.tsx create this Stack.Screen:
    • In this order index, signup, and +not-found.
  • Define the parent route; add a Stack.Screen for (auth) above (tabs) in _layout.tsx.
  • ***Note: by default the header shows for Stack.Screen components; it can be hidden by setting the option, headerShown, to false.
  • KEY: expo is a file based routing system; Because the folder structure, (auth) then (tabs), is already defined since its a file based system, it still shows even if the route isn’t defined explicitly in _layout.tsx: https://youtu.be/bxKbv1KZVkI?si=ZHhua1pRTog-R4YO\&t=746
  • Change the Text components text to “Login” for (auth)/index.tsx.
  • Place a Link component with a href property equal to “/(tabs)” and text saying “Home”.
    • ***Note:This allows us to navigate to the home screen or Tabs navigation menu, (tabs), without logging in for now.
  • To perform linking in expo router:
    • Use the Link component:

    • Import router from useRouter and use a regular React Native component:


3 - Adding Custom Icons to the Bottom Tab Bar in a TikTok Clone with React Native

  • Expo’s expo/vector-icons package contains free to use expo icons: https://icons.expo.fyi/Index
  • Filter the icons on the site by Ionicons.
  • Search for the home icon and click on it to import and render the component in (tabs)/_layout.tsx.
  • Do the same for the rest of the tab icons:
    • Friends: people, Camera: add-circle, Inbox: chatbox-ellipses, Profile: person.
      • ***Note: On android instead of wrapping Ionicons in the View component add this:
  • Add the focused property to the Ionicons component so that when selected the icon switches to an outline.
    • Home: home-outline, People: people-outline, Inbox: chatbox-ellipses-outline, Profile: person-outline.
**4 - Integrating Supabase for Authentication and Database in a TikTok CloneReact Native**
  • Superbase is a Backend-as-a-Service (BaaS) that provides authentication, storage, and PostgreSQL database and is similar to Firebase. Here are the Expo and Supabase docs: https://docs.expo.dev/guides/using-supabase/
    https://supabase.com/docs
  • Follow the Install and Initialize the Supabase Typescript SDK section of the expo docs to get started.
  • Set up a Supabase account here: https://supabase.com/
  • Create a new project.
    • ***Note: Make sure to put your database password somewhere safe!
  • Create a new .env and .env.local file in root and add them to the .gitignore.
  • Within .env.local, create these variables to store the environment variables from Supabase:
    • EXPO_PUBLIC_SUPABASE_URL, EXPO_PUBLIC_SUPABASE_ANON_KEY, DATABASE_URL, DIRECT_URL.
  • Find the EXPO_PUBLIC_SUPABASE_URL under Project Settings > Data API.
  • Find EXPO_PUBLIC_SUPABASE_ANON_KEY under Project Settings > API Key > Legacy API Keys.
  • Find both DATABASE_URL and DIRECT_URL at the top under Connect > ORMs.
  • Create a new folder called utils and inside it create a new file called supabase.ts.
  • ***Note: install react-native-async-storage/async-storage and use this for utils/supabase.ts instead:
  • Replace the default supabaseUrl and supabasePublishableKey in utils/supabase.ts with process.env.EXPO_PUBLIC_SUPABASE_URL and process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY, respectively.
**5 - Setting Up Prisma for Database Management in a TikTok Clone with SupabaseReact Native**
  • Install Prisma with npm install prisma --save-dev.
    • ***Note: --save-dev tells npm to add the installed package, prisma here, as a development dependency.
  • Initialize Prisma with postgresql by running npx prisma init --datasource-provider postgresql.
    • ***Note: --datasource-provider specifies the database provider, postgresql here, that Prisma should configure in the generated schema.prisma.
    • ***Note: remove output in schema.prisma.
  • Run npx prisma db pull to connect to the Supabase database, read its schema, and generate or update the Prisma schema file.
  • Run npx prisma generate to read the Prisma schema file and generate the Prisma Client library.
  • Create a user model (table) that looks like this:
  • Run npx prisma format to clean up formatting in schema.prisma.
  • Run npx prisma db push to update Supabases database schema with schema.prisma.
    • ***Note: change url: env(“DATABASE_URL”) to url: env(“DIRECT_URL”) in prisma.config.ts.
    • ***Note: don’t forget to change the [YOUR-PASSWORD] part of the DIRECT_URL and DATABASE_URL.
  • The User table will have and id, username, email, created_at (time user created), videos, likes, followers, comments, and chats fields:
    • ***Note: videos-chats items are called associations, they are relational fields associated with other models in the schema. These associations define how users relate to other models items in the database, such as videos uploaded, likes given, etc.
  • The Video table will have id, title, uri, user_id, user, like, created_at, and Comment:
    • ***Note: dbgenerated(“uuid_generate_v4()”) is a database value generated by PostgreSQL using the uuid_generate_v4() function; Prisma isn’t responsible for making this value.
    • ***Note: it requires the uuid-ossp extension added here:
    • ***Note: the user field has a relation to the User model. The foreign key (relation to another model, User here) is user_id which references the id field in User. If the User is deleted, all records in the Video model are deleted automatically.
  • The Like table will have id, user_id, user, video_id, video, video_user_id, and created_at fields:
  • The Follower table will have id, user_id, user, follower_user_id, and created_at fields:
  • The Comment table will have id, user_id, user, video_id, video, video_user_id, text, and created_at fields:
  • The Chat table will have id, user_id, user, chat_user_id, users_key, text, and created_at fields:
  • ***Note: in the generator client block add a previewFeatures field and set it equal to [“postgresqlExtension”]; This is required to use the Supabase the uuid-ossp extension.
  • Run npx prisma db push to push to update the Supabase schema with the new models.
  • Run npx prisma format to format schema.prisma.
  • All tables should be in Supabase.

6 - Implementing Authentication in a TikTok Clone with Supabase and React Native

  • Inside (auth)/index.tsx’s the exported function create two state variables:
    • Email which has a setEmail function to update the value email.
    • Password which has a setPassword function to update the password.
  • React.useState(*initialValue*) returns an array with two elements:
    • The current state value (e.g. email or password)
    • A function to update that value (e.g. setEmail or setPassword)
  • ***Note: The setFunctions* will be passed into the onChangeText field for the TextInput components and saves the last thing typed. The handleLogin arrow function will print the values stored in the state variables when the user presses the Login button (TouchableOpacity component).
  • Copy (auth)/index.tsx into (auth)/signup.tsx.
  • Add a Signup button that routes to the (auth)/signup.tsx to the Login page using another TouchableOpacity component with an onPress property that calls router.push(‘/signup).
    • Make the (auth)/signup.tsx page modal (page that slides up from the bottom) by adding the presentation: “modal” property to the options property on the Stack.Screen component in (auth)/_layout.tsx for (auth)/signup.tsx.
  • Add another state variable, username, and create another TextInput component for a username field on (auth)/signup.tsx.
  • Import supabase for user account creation authentication into (auth)/signup.tsx
  • ***Note: the async in the function below waits for the supabase.auth.signUp function to return a promise (Supabase sign in request) to finish before continuing.
  • supabase.auth.signUp is an asynchronous function that sends a request to Supabase’s authentication service to create a new user.
  • It returns a promise that resolves with the result of the signup request.
  • ***Note: await tells TypeScript “Pause here until Supabase finishes creating the account, then give me the result.”
  • supabase.auth.signUp returns 2 objects:
    • data which contains information about the sign up result.
    • error which contains any errors caught if something went wrong.
  • router.back() takes the user back to the previous page.
  • supabase.from(‘User’).insert tells Supabase to insert a new item from the User table.
  • supabase.auth.signInWithPassword request sign in authentication through Supabase for a user with matching email and password.
  • ***Note: temporarily disable Confirm email from Authentication > Sign In/Providers in Supabase for testing.
  • Instead of using supabase.auth create an authentication provider that will reference a user object multiple times without calling it.
  • A provider component supplies functionality or data to other parts of an app.
  • Breakdown of providers/AuthProvier.tsx file:
    • AuthContext creates a context object that has a user object (required state on all pages), signIn method, signUp method, and signOut method.
    • user object is the state that every page needs access to
    • signIn method will call supabase.auth.signInWithPassword() to log in users if they have a valid email and password in the User table
    • signUp method will call supabase.auth.signUp to sign up users with a new username, email, and password
    • signOut method will call supabase.auth.signOut to sign out users.
    • getUser will call supabase.from(‘User’).select(‘*’).eq(‘id’, id).single() to retrieve the user from the table using their id.
      • single() tells Supabase to store a single User object in data instead of an array of User objects.
  • How signing in works logically:
    • From /(auth)/index.tsx when a user signs in it calls the signIn function in /providers/AuthProvider.
    • signIn then calls signInWithPassword to query the database (Supabase), retrieving the user object and storing it in data if it exists, and passes the user id from data to getUser
    • getUser then retrieves a single column with the matching user id if it exists, and calls setUser(data) to set the user object to match the current user’s credentials.

7 - Implementing Camera Functionality in a TikTok Clone with React Native

  • Supabase’s onAuthStateChange function listens for changes in authentication state (whether user is signed in or out).
  • Expo docs for adding camera functionality to apps: https://docs.expo.dev/versions/latest/sdk/camera/
  • The Basic Camera Usage code is good for most apps.
    • ***Note: NativeWind and custom styling won’t work on camera components.
  • The React.useRef<CameraView>() is a React Hook that lets you reference a value that is not needed for rendering.
    • Here it is used with the react-native-vision-camera library allowing us to use important methods such as:
    • takePhoto() to allow the user to take a photo.
    • recordAsync() to allow the user to start recording a video.
    • stopRecording() to allow the user to stop recording a video.
  • A Storage > Bucket is Supabase is a container (folder-like space) where you store and manage files such as:
    • Images, videos, audio, pdfs, any binary or text files.

8 - Adding Image Picker and Video Preview to a TikTok Clone with React Native and Supabase