Next.js - advanced (part 1)
Working with Prisma gives you a best-in-class TypeScript ORM, a declarative database migration system, and a database with everything you need to get started
SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine. SQLite is the most used database engine in the world.
npx create-next-app@15.5.2
npm install prisma --save-dev
npx prisma init --datasource-provider sqlite --output ../src/app/_generated/prismanpx prisma migrate dev --name initimport { PrismaClient } from "@/app/_generated/prisma";
const globalForPrisma = global as unknown as {
prisma: PrismaClient;
};
const prisma = globalForPrisma.prisma || new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
export default prisma;When you want to interact with the database,
import the prisma object and go!
import prisma from "@/lib/client";
export default async function Books() {
const books = await prisma.book.findMany();
return (
<div>
<ul>
{books.map((book) => {
return <li key={book.id}>{book.title}</li>;
})}
</ul>
</div>
);
}
Got lost somewhere in this set-up process?
Make sure to check out the recording!
Next.js - advanced (part 1)
| Field type (Prisma) | JavaScript type | SQLite type |
|---|---|---|
| String | string | TEXT |
| Boolean | boolean | INTEGER |
| Int | number | INTEGER |
| BigInt | BigInt | INTEGER |
| Float | number | REAL |
| Decimal | decimal.js | DECIMAL |
| DateTime | Date | NUMERIC |
const a = 0.1 + 0.2;
// what is the value of a?Next.js - advanced (part 1)
A Component Library is an organized collection of pre-designed and pre-built user interface (UI) elements that can be reused across various projects. These elements often include items like buttons, fonts, accordions, or even larger segments such as headers or footers. The primary aim of a component library is to standardize development, minimize code duplication, and drive scalability within digital products.
- Sanity.io
Examples:
→ feel free to use one or none for your assignment.
We'll use Radix Themes for in-class examples/exercises.
Oefening (deel 2):
Next.js - advanced (part 1)
Oefening (deel 3):
Forms - Optie 1: React Server Actions
export default function NewItemPage() {
async function createItem(formData: FormData) {
"use server";
const rawFormData = {
/* formData.get() returns een value met type File | string | null.
Daarom moeten we de TS compiler helpen met casting of narrowing */
description: formData.get("description") as string ?? ""
}
// do something here e.g. create an item in the database
}
return (
<form action={createItem}>
<input type="text" name="description" />
<button type="submit">Submit</button>
</form>
);
}Oefening (deel 4):
// This is an example of programmatic navigation in a client component
"use client";
import { useRouter } from "next/router";
export function Page() {
const router = useRouter();
function onClick() {
console.log("Do something else here instead of logging ... !");
router.push("/about");
}
return (
<div>
<button onClick={onClick}>Go to about page</button>
</div>
);
}
// This is an example of programmatic navigation in a server component
export default function NewItemPage() {
async function createItem(formData: FormData) {
"use server";
// do something here e.g. create an item in the database
redirect("/items");
}
return (
<form action={createItem}>
<input type="text" name="description" />
<button type="submit">Submit</button>
</form>
);
}Oefening (deel 5):
Forms - Optie 2:
How can we create an API endpoint in Next.js?
import prisma from "@/lib/client.ts";
export async function POST(request: Request) {
// do something here ...
}Side quest (lees: huiswerk):
Next.js - advanced (part 1)
Seeding: consistently recreating the same data
// File: prisma/seed.ts
// Important: do NOT use the import alias (@) but use a relative path
import { PrismaClient } from "../src/app/_generated/prisma";
const prisma = new PrismaClient();
async function main() {
await prisma.task.deleteMany();
const tasks = await prisma.task.createMany({
data: [ ... ],
});
console.log(tasks);
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
// File: package.json
{
...,
"devDependencies": {
...
},
"prisma": {
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
},
}
npm install -g ts-nodenpx prisma db seed
...
Running seed command `ts-node --compiler-options {"module":"CommonJS"} ...
{ count: 5 }
🌱 The seed command has been executed.Oefening (deel 6):
Next.js - advanced (part 1)
Recap:
In Prisma, we need to:
model User {
id Int @id @default(autoincrement())
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
author User @relation(fields: [authorId], references: [id])
authorId Int
}
// The fields author and posts do not exist in the database// Example of how to create nested records:
// https://www.prisma.io/docs/orm/prisma-schema/data-model/relations#create-a-record-and-nested-records
const userAndPosts = await prisma.user.create({
data: {
posts: {
create: [
// Populates authorId with user's id
{ title: 'Prisma Day 2020' },
// Populates authorId with user's id
{ title: 'How to write a Prisma schema' },
],
},
},
});Oefening (deel 7):
Oefening (deel 7):
Oefening (deel 7):
To include related data in our queries:
const users = await prisma.user.findMany({
include: {
posts: true,
},
});Oefening (deel 8):
Oefening (deel 8):
→ Huiswerk!