21
How to Use React + Supabase Pt 2: Working with the Database
This demo will teach you how to connect a React application with Supabase.
If you want to learn more about Supabase in general or how to set up authentication easily using supabase in a react application, read this post
We will use an Object Relational Mapper (ORM) to interact with our database. We will go with Prisma for this demo since it's highly popular, well maintained, and easy to set up. If you want you can use another ORM since Knex, TypeORM, Sequelize, and others are great too so feel free to follow along with those if you are more familiar with them.
If you are familiar with graphql you will find Prisma a breeze to pick up.
Install Prisma
yarn add prisma
It's possible to do everything we are going to with an ORM also without one. You can write raw SQL scripts or use the Supabase UI to do all of these tasks.
The reason that I am using an ORM for this is so that we can have our SQL interactions coded and saved in source control to make it easier to troubleshoot, scale, and collaborate.
Feel free to write raw SQL, use the SupabaseUI, or a different ORM if you would like, but an ORM makes this much easier.
Run:
npx prisma init
This will create a new file called schema.prisma
in a new prisma
directory.
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = "<YOUR_DB_CONNECTION_STRING>"
}
Replace this with your connection string for the supabase DB you created in the previous post.
Be careful with these sensitive values. You will want to make sure that they remain secrets, so don't push these to github in a public repo. For this demo we will be hard coding them to just keep things simple.
Your connection string should look like this: postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=SCHEMA
Creating models with Prisma has a bit of a learning curve. Check out the docs as you build out these models.
For now, copy and paste this into the prisma/schema.prisma
file.
...
model User {
id Int @id @default(autoincrement())
firstName String
lastName String
email String
}
We will create a small Customer Relationship Manager. Here we just have a simple User
model to get us started.
Next we need to create our migrations. This is extremly simple and can be done automatically with Prisma.
Run the command:
npx prisma migrate dev --name init
You will see a migrations
folder created in the prisma
directory. If you navigate to your project in the Supabase UI, you will see the are now tables created! One is named User
and was created from our migration. (Another table is _prisma_migrations
and is used by Prisma to internally keep track of which migrations have been created or rolledback).
Because we are using Prisma, the next step before we can seed and query our DB is to install the Prisma client.
yarn add @prisma/client
Now we will create a new file in the prisma
directory called prismaClient.js
with the following code.
const { PrismaClient } = require('@prisma/client')
const prisma = new PrismaClient()
module.exports = prisma
Now it's time to seed the database. Let's create a file called seedDb.js
in the prisma
directory that imports the prismaClient
we just created and seeds the DB with some dummy data.
We will use faker
to create some fake names for the dummy data.
const prisma = require('./prismaClient.js')
const faker = require('faker')
const users = []
function createUsers(){
const num = 100;
let x = 0;
while(x < 100){
const user = {
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
email: faker.internet.email(),
}
users.push(user)
x++
}
}
async function seedDb(){
await prisma.user.createMany({data: users})
}
async function main() {
createUsers()
await seedDb()
}
main().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
Now that we can create tables with migrations and write to tables using our ORM, we are ready to get back into our React app and perform CRUD applications on this data.
The migrations and seeding in the previous step give us some data tables and mock data to work with here.
From now on, in our react app, we will be using the supabase client to interact with our database.
First let's create a new folder called components
in the src
directory.
Then in the src/components
directory, we will create a new component called Users.jsx
, which will looks like this:
import { useEffect, useState } from "react";
import supabase from "../supabase";
export default function () {
const [loading, setLoading] = useState(true);
const [users, setUsers] = useState([]);
async function getUsers() {
const { data, error } = await supabase.from("User").select();
setUsers(u => u= data);
}
useEffect(() => {
setLoading(true);
getUsers();
setLoading(false);
}, []);
return (
<>
<h2>Users</h2>
{loading ? (
<p>loading...</p>
) : (
<>
{users?.length ? (
<ul>
{users.map((user) => (
<li>
{user.email} : {user.firstName} {user.lastName}
</li>
))}
</ul>
) : (
<p>No users currently</p>
)}
</>
)}
</>
);
}
In theory, this will print every user's email and name.
We don't want to do that unless the user is logged in, so let's update our App.js
file to look like this:
import "./App.css";
import supabase from "./supabase";
import { useState, useEffect } from "react";
import Users from "./components/Users";
function App() {
const [user, setUser] = useState(null);
supabase.auth.onAuthStateChange((event, session) => {
if (session?.user) {
setUser((u) => (u = session.user));
}
});
async function signInWithGithub() {
const { user, session, error } = await supabase.auth.signIn({
provider: "github",
});
}
async function signOut() {
const { error } = await supabase.auth.signOut();
setUser((u) => (u = null));
}
return (
<div className="App">
{!user ? (
<button onClick={signInWithGithub}>Sign In With Github</button>
) : (
<>
<button onClick={signOut}>Log Out, {user?.email}</button>
<Users />
</>
)}
</div>
);
}
export default App;
Now, the user will be presented with a Log In button if not authenticated, and if they are authenticated we should see a list of all of our user's email and names.
To write, update, get real-time updates, create stored-procedures, use storage and the many more features of Supabase, check out the Supabase JS client docs. They are easy to follow and very helpful.
Hopefully this got you started with Supabase and you can be well on your way to building real-time authenticated web apps quickly without the overhead of managing a DB and API.
If you like this post and it helped you, share it with friends.
21