From 9ece454e0d2968f51834efee7aa204a8d8c2f66d Mon Sep 17 00:00:00 2001
From: Daniel Steigerwald
Date: Tue, 5 Dec 2023 00:07:27 +0100
Subject: [PATCH] Update Next.js example
---
examples/nextjs/app/page.tsx | 83 +++++++++++++++++++++---------------
examples/nextjs/package.json | 22 +++++-----
2 files changed, 59 insertions(+), 46 deletions(-)
diff --git a/examples/nextjs/app/page.tsx b/examples/nextjs/app/page.tsx
index b38a44c60..0a15fa876 100644
--- a/examples/nextjs/app/page.tsx
+++ b/examples/nextjs/app/page.tsx
@@ -2,7 +2,22 @@
import { TreeFormatter } from "@effect/schema";
import * as S from "@effect/schema/Schema";
-import * as Evolu from "@evolu/react";
+import {
+ EvoluProvider,
+ NonEmptyString1000,
+ SqliteBoolean,
+ String,
+ canUseDom,
+ cast,
+ createEvolu,
+ id,
+ jsonArrayFrom,
+ parseMnemonic,
+ useEvolu,
+ useEvoluError,
+ useOwner,
+ useQuery,
+} from "@evolu/react";
import { Effect, Exit } from "effect";
import {
ChangeEvent,
@@ -14,23 +29,23 @@ import {
useState,
} from "react";
-const TodoId = Evolu.id("Todo");
+const TodoId = id("Todo");
type TodoId = S.Schema.To;
-const TodoCategoryId = Evolu.id("TodoCategory");
+const TodoCategoryId = id("TodoCategory");
type TodoCategoryId = S.Schema.To;
-const NonEmptyString50 = Evolu.String.pipe(
+const NonEmptyString50 = String.pipe(
S.minLength(1),
S.maxLength(50),
- S.brand("NonEmptyString50"),
+ S.brand("NonEmptyString50")
);
type NonEmptyString50 = S.Schema.To;
const TodoTable = S.struct({
id: TodoId,
- title: Evolu.NonEmptyString1000,
- isCompleted: S.nullable(Evolu.SqliteBoolean),
+ title: NonEmptyString1000,
+ isCompleted: S.nullable(SqliteBoolean),
categoryId: S.nullable(TodoCategoryId),
});
type TodoTable = S.Schema.To;
@@ -49,18 +64,16 @@ const Database = S.struct({
todo: TodoTable,
todoCategory: TodoCategoryTable,
});
+type Database = S.Schema.To;
-const evolu = Evolu.create(Database);
-
-// React Hooks
-const { useEvolu, useEvoluError, useQuery, useOwner } = evolu;
+const evolu = createEvolu(Database);
const createFixtures = (): Promise =>
Promise.all(
evolu.loadQueries([
evolu.createQuery((db) => db.selectFrom("todo").selectAll()),
evolu.createQuery((db) => db.selectFrom("todoCategory").selectAll()),
- ]),
+ ])
).then(([todos, categories]) => {
if (todos.row || categories.row) return;
@@ -69,16 +82,16 @@ const createFixtures = (): Promise =>
});
evolu.create("todo", {
- title: S.parseSync(Evolu.NonEmptyString1000)("Try React Suspense"),
+ title: S.parseSync(NonEmptyString1000)("Try React Suspense"),
categoryId: notUrgentCategoryId,
});
});
const isRestoringOwner = (isRestoringOwner?: boolean): boolean => {
- if (!Evolu.canUseDom) return false;
+ if (!canUseDom) return false;
const key = 'evolu:isRestoringOwner"';
if (isRestoringOwner != null)
- localStorage.setItem(key, String(isRestoringOwner));
+ localStorage.setItem(key, isRestoringOwner.toString());
return localStorage.getItem(key) === "true";
};
@@ -95,7 +108,7 @@ const NextJsExample = memo(function NextJsExample() {
});
return (
- <>
+
@@ -116,7 +129,7 @@ const NextJsExample = memo(function NextJsExample() {
- >
+
);
});
@@ -144,29 +157,29 @@ const todosWithCategories = evolu.createQuery((db) =>
db
.selectFrom("todo")
.select(["id", "title", "isCompleted", "categoryId"])
- .where("isDeleted", "is not", Evolu.cast(true))
+ .where("isDeleted", "is not", cast(true))
// Filter null value and ensure non-null type. Evolu will provide a helper.
.where("title", "is not", null)
- .$narrowType<{ title: Evolu.NonEmptyString1000 }>()
+ .$narrowType<{ title: NonEmptyString1000 }>()
.orderBy("createdAt")
// https://kysely.dev/docs/recipes/relations
.select((eb) => [
- Evolu.jsonArrayFrom(
+ jsonArrayFrom(
eb
.selectFrom("todoCategory")
.select(["todoCategory.id", "todoCategory.name"])
- .where("isDeleted", "is not", Evolu.cast(true))
- .orderBy("createdAt"),
+ .where("isDeleted", "is not", cast(true))
+ .orderBy("createdAt")
).as("categories"),
- ]),
+ ])
);
const Todos: FC = () => {
- const { create } = useEvolu();
const { rows } = useQuery(todosWithCategories);
+ const { create } = useEvolu();
const handleAddTodoClick = (): void => {
- prompt(Evolu.NonEmptyString1000, "What needs to be done?", (title) => {
+ prompt(NonEmptyString1000, "What needs to be done?", (title) => {
create("todo", { title });
});
};
@@ -190,14 +203,14 @@ const TodoItem = memo<{
}>(function TodoItem({
row: { id, title, isCompleted, categoryId, categories },
}) {
- const { update } = useEvolu();
+ const { update } = useEvolu();
const handleToggleCompletedClick = (): void => {
update("todo", { id, isCompleted: !isCompleted });
};
const handleRenameClick = (): void => {
- prompt(Evolu.NonEmptyString1000, "New Name", (title) => {
+ prompt(NonEmptyString1000, "New Name", (title) => {
update("todo", { id, title });
});
};
@@ -270,15 +283,15 @@ const todoCategories = evolu.createQuery((db) =>
db
.selectFrom("todoCategory")
.select(["id", "name", "json"])
- .where("isDeleted", "is not", Evolu.cast(true))
+ .where("isDeleted", "is not", cast(true))
// Filter null value and ensure non-null type. Evolu will provide a helper.
.where("name", "is not", null)
.$narrowType<{ name: NonEmptyString50 }>()
- .orderBy("createdAt"),
+ .orderBy("createdAt")
);
const TodoCategories: FC = () => {
- const { create } = useEvolu();
+ const { create } = useEvolu();
const { rows } = useQuery(todoCategories);
// Evolu automatically parses JSONs into typed objects.
@@ -308,7 +321,7 @@ const TodoCategories: FC = () => {
const TodoCategoryItem = memo<{
row: Pick;
}>(function TodoItem({ row: { id, name } }) {
- const { update } = useEvolu();
+ const { update } = useEvolu();
const handleRenameClick = (): void => {
prompt(NonEmptyString50, "Category Name", (name) => {
@@ -337,8 +350,8 @@ const OwnerActions: FC = () => {
const [showMnemonic, setShowMnemonic] = useState(false);
const handleRestoreOwnerClick = (): void => {
- prompt(Evolu.NonEmptyString1000, "Your Mnemonic", (mnemonic) => {
- Evolu.parseMnemonic(mnemonic)
+ prompt(NonEmptyString1000, "Your Mnemonic", (mnemonic) => {
+ parseMnemonic(mnemonic)
.pipe(Effect.runPromiseExit)
.then(
Exit.match({
@@ -349,7 +362,7 @@ const OwnerActions: FC = () => {
isRestoringOwner(true);
evolu.restoreOwner(mnemonic);
},
- }),
+ })
);
});
};
@@ -404,7 +417,7 @@ const Button: FC<{
const prompt = (
schema: S.Schema,
message: string,
- onSuccess: (value: To) => void,
+ onSuccess: (value: To) => void
): void => {
const value = window.prompt(message);
if (value == null) return; // on cancel
diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json
index 96babf96b..fee19a17f 100644
--- a/examples/nextjs/package.json
+++ b/examples/nextjs/package.json
@@ -9,20 +9,20 @@
"lint": "next lint"
},
"dependencies": {
- "@evolu/react": "^2.0.7",
+ "@evolu/react": "^3.0.0",
"next": "14.0.3",
- "react": "^18",
- "react-dom": "^18"
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
},
"devDependencies": {
- "@types/node": "^20",
- "@types/react": "^18",
- "@types/react-dom": "^18",
- "autoprefixer": "^10.0.1",
- "eslint": "^8",
+ "@types/node": "^20.10.3",
+ "@types/react": "^18.2.42",
+ "@types/react-dom": "^18.2.17",
+ "autoprefixer": "^10.4.16",
+ "eslint": "^8.55.0",
"eslint-config-next": "14.0.3",
- "postcss": "^8",
- "tailwindcss": "^3.3.0",
- "typescript": "^5"
+ "postcss": "^8.4.32",
+ "tailwindcss": "^3.3.6",
+ "typescript": "^5.3.2"
}
}