Eldon
Eldon
TTCTheo's Typesafe Cult
Created by Eldon on 8/21/2024 in #questions
Next.js Use localStorage For Rendering Without Flash?
Hello, I am trying to grab data from localStorage and use it to change the text in a button. This system should detect if a user has clicked the button before and say "continue" instead of "start." I made a useUserHistory hook to wrap this behaviour.
import { useEffect, useReducer, useState } from "react";

export type UserHistoryObject = {
[key: string]: string;
};

export interface UserHistory {
userHistory: UserHistoryObject;
setUserHistory: (pv: UserHistoryObject) => void;
getBoolean: (item: string) => boolean;
setBoolean: (item: string, value: boolean) => void;
getNumber: (item: string) => number;
setNumber: (item: string, value: number) => void;
getString: (item: string) => string;
setString: (item: string, value: string) => void;
clearUserHistory: () => void;
}

export default function useUserHistory(): UserHistory {
const [userHistory, setUserHistory] = useState({} as any);

useEffect(() => {
if (
localStorage.getItem("userHistory") &&
Object.keys(userHistory).length === 0
) {
setUserHistory(JSON.parse(localStorage.getItem("userHistory") as string));
}
}, []);

useEffect(() => {
if (
localStorage.getItem("userHistory") &&
Object.keys(userHistory).length === 0
)
return;
localStorage.setItem("userHistory", JSON.stringify(userHistory));
}, [userHistory]);

return {
userHistory,
setUserHistory,
getBoolean: (item) => userHistory?.[item] === "true" || false,
setBoolean: (item, value) => {
const newUserHistory = { ...userHistory };
newUserHistory[item] = String(value);
setUserHistory(newUserHistory);
},
getNumber: (item) => Number(userHistory?.[item]),
setNumber: (item, value) => {
const newUserHistory = { ...userHistory };
newUserHistory[item] = String(value);
setUserHistory(newUserHistory);
},
getString: (item) => userHistory?.[item],
setString: (item, value) => {
const newUserHistory = { ...userHistory };
newUserHistory[item] = value;
setUserHistory(newUserHistory);
},
clearUserHistory: () => {
setUserHistory({});
},
};
}
import { useEffect, useReducer, useState } from "react";

export type UserHistoryObject = {
[key: string]: string;
};

export interface UserHistory {
userHistory: UserHistoryObject;
setUserHistory: (pv: UserHistoryObject) => void;
getBoolean: (item: string) => boolean;
setBoolean: (item: string, value: boolean) => void;
getNumber: (item: string) => number;
setNumber: (item: string, value: number) => void;
getString: (item: string) => string;
setString: (item: string, value: string) => void;
clearUserHistory: () => void;
}

export default function useUserHistory(): UserHistory {
const [userHistory, setUserHistory] = useState({} as any);

useEffect(() => {
if (
localStorage.getItem("userHistory") &&
Object.keys(userHistory).length === 0
) {
setUserHistory(JSON.parse(localStorage.getItem("userHistory") as string));
}
}, []);

useEffect(() => {
if (
localStorage.getItem("userHistory") &&
Object.keys(userHistory).length === 0
)
return;
localStorage.setItem("userHistory", JSON.stringify(userHistory));
}, [userHistory]);

return {
userHistory,
setUserHistory,
getBoolean: (item) => userHistory?.[item] === "true" || false,
setBoolean: (item, value) => {
const newUserHistory = { ...userHistory };
newUserHistory[item] = String(value);
setUserHistory(newUserHistory);
},
getNumber: (item) => Number(userHistory?.[item]),
setNumber: (item, value) => {
const newUserHistory = { ...userHistory };
newUserHistory[item] = String(value);
setUserHistory(newUserHistory);
},
getString: (item) => userHistory?.[item],
setString: (item, value) => {
const newUserHistory = { ...userHistory };
newUserHistory[item] = value;
setUserHistory(newUserHistory);
},
clearUserHistory: () => {
setUserHistory({});
},
};
}
Only this version results in no error, but it always flashes "Start" until the value is retrieved. When I use
const [userHistory, setUserHistory] = useState(JSON.parse(localStorage.getItem("userHistory") || "{}"));
const [userHistory, setUserHistory] = useState(JSON.parse(localStorage.getItem("userHistory") || "{}"));
and remove the first useEffect, it seems to work, but I do get a error for localStorage not being defined. I understand this is due to the server pre-rendering the initial value of useState, a behaviour I do not want in this case. Should I rethink this entire system?
8 replies
TTCTheo's Typesafe Cult
Created by Eldon on 4/18/2024 in #questions
Drizzle Not Working At All On Backend
Hello, I am using drizzle to make a password for me for my website which using a TOTP. I am using Create T3 with Drizzle to store the private key on the backend along with the validity and expiry. All calls to my Postgresql server result in extremely unuseful errors. Using Drizzle studio I can make calls to the database, but not from the backend. Here's my code, most of it is similar to a stock Create T3 app.
// /src/server/db/index.ts

import 'server-only';

import { drizzle } from "drizzle-orm/vercel-postgres";

// import { env } from "~/env";
import * as schema from "./schema";
import { sql } from '@vercel/postgres';

export const db = drizzle(sql, { schema, logger: true, });
// /src/server/db/index.ts

import 'server-only';

import { drizzle } from "drizzle-orm/vercel-postgres";

// import { env } from "~/env";
import * as schema from "./schema";
import { sql } from '@vercel/postgres';

export const db = drizzle(sql, { schema, logger: true, });
// /src/server/db/schema.ts

import { sql } from "drizzle-orm";
import {
boolean,
integer,
pgTableCreator,
serial,
timestamp,
varchar,
} from "drizzle-orm/pg-core";

export const createTable = pgTableCreator((name) => `${process.env.DB_CONTAINER_NAME}_${name}`);

export const hotlinks = createTable(
"hotlink",
{
id: serial("id").primaryKey(),
url: varchar("url", { length: 256 }).unique(),
pointer: varchar("pointer", { length: 256 }),
createdAt: timestamp("created_at")
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
expiresAt: timestamp("expires_at"),
ttl: integer("ttl"),
}
);

export const authentications = createTable(
"authentication",
{
id: serial("id").primaryKey(),
active: boolean("active").default(true),
createdAt: timestamp("created_at")
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
updatedAt: timestamp("updatedAt").defaultNow(),
key: varchar("formatted_key", { length: 256 }),
}
);
// /src/server/db/schema.ts

import { sql } from "drizzle-orm";
import {
boolean,
integer,
pgTableCreator,
serial,
timestamp,
varchar,
} from "drizzle-orm/pg-core";

export const createTable = pgTableCreator((name) => `${process.env.DB_CONTAINER_NAME}_${name}`);

export const hotlinks = createTable(
"hotlink",
{
id: serial("id").primaryKey(),
url: varchar("url", { length: 256 }).unique(),
pointer: varchar("pointer", { length: 256 }),
createdAt: timestamp("created_at")
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
expiresAt: timestamp("expires_at"),
ttl: integer("ttl"),
}
);

export const authentications = createTable(
"authentication",
{
id: serial("id").primaryKey(),
active: boolean("active").default(true),
createdAt: timestamp("created_at")
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
updatedAt: timestamp("updatedAt").defaultNow(),
key: varchar("formatted_key", { length: 256 }),
}
);
6 replies