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", |