This tutorial will show you how to persist user inputs after form submit in Remix.
- Remix installed
import type { Remix } from "@remix-run/dom"; | |
import { press } from "@remix-run/events/press"; | |
function Component(this: Remix.Handle) { | |
let isMounted = false; | |
let renderCount = 0; | |
// Runs once after first render (setup phase) | |
this.queueTask(() => { | |
isMounted = true; |
import { hydrated, type Remix } from "@remix-run/dom"; | |
import { press } from "@remix-run/events/press"; | |
import { | |
QueryClient, | |
QueriesObserver, | |
type QueryObserverOptions, | |
} from "@tanstack/query-core"; | |
type Todo = { | |
userId: number; |
import type { Remix } from "@remix-run/dom"; | |
import { press } from "@remix-run/events/press"; | |
import { state } from "./state"; | |
export function Counter(this: Remix.Handle, { initial }: { initial?: number }) { | |
let [count, setCount] = state(this, initial ?? 0); | |
return () => ( | |
<button type="button" on={[press(() => setCount((c) => c + 1))]}> |
import { index, prefix, route } from "@react-router/dev/routes"; | |
import { camelize, pluralize, singularize } from "inflected"; | |
function createCrud(base = "./views") { | |
/** | |
* Create a CRUD route configuration. | |
* @param name The name of the resource. It will be pluralized for the path. | |
* @param options The options for the crud. | |
* @param options.member Extra routes to add to each member. | |
* @param options.collection Extra routes to add to the collection. |
import Auth0 from "@auth/core/providers/auth0"; | |
import { RemixAuth } from "~/services/auth" | |
import { sessionStorage } from "~/services/session.server"; | |
export let { loader, action } = RemixAuth({ | |
sessionStorage: sessionStorage, // this does nothing yet | |
secret: process.env.AUTH_SECRET ?? "s3cr3t", | |
providers: [ | |
Auth0({ |
This tutorial will show you how to persist user inputs after form submit in Remix.
module.exports = { | |
theme: { | |
screens: { | |
"-2xl": { max: "1536px" }, | |
"-xl": { max: "1280px" }, | |
"-lg": { max: "1024px" }, | |
"-md": { max: "768px" }, | |
"-sm": { max: "640px" }, | |
"sm~md": { min: "640px", max: "768px" }, | |
"md~lg": { min: "768px", max: "1024px" }, |
import { test, expect, describe, beforeAll, afterAll } from "vitest"; | |
import "pptr-testing-library/extend"; | |
import { type App, start } from "test/helpers/app"; | |
import { loader } from "./articles"; | |
import { logger } from "~/services/logger.server"; | |
import type { PrismaClient } from "@prisma/client"; | |
import { createDatabaseClient } from "test/helpers/db"; | |
describe("E2E", () => { | |
let app: App; |
import { renderToStream } from "@react-pdf/renderer"; | |
import ReactDOMServer from "react-dom/server"; | |
import { EntryContext, Headers, RemixServer, Request, Response } from "remix"; | |
import PDF, { loader } from "./pdfs/my-pdf.server"; | |
async function handlePDFRequest(request: Request, headers: Headers) { | |
// get the data for the PDF | |
let response = await loader({ request, context: {}, params: {} }); | |
// if it's a response return it, this means we redirected | |
if (response instanceof Response) return response; |
/* eslint-disable unicorn/prefer-module */ | |
module.exports = { | |
root: true, | |
parser: "@typescript-eslint/parser", | |
plugins: [ | |
"@typescript-eslint", | |
"unicorn", | |
"import", | |
"react", | |
"prettier", |