DEV Community

Alex Spinov
Alex Spinov

Posted on

Remix Has a Free React Framework That Embraces Web Standards — Loaders, Actions, and Progressive Enhancement

The Next.js Problem

Next.js: App Router vs Pages Router. Server Components vs Client Components. 'use client' directives everywhere. The mental model keeps changing.

Remix uses web standards. Request/Response, FormData, HTTP caching. Patterns that work with or without JavaScript.

What Remix Gives You

Loaders (Server Data)

import { json, LoaderFunction } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';

export const loader: LoaderFunction = async ({ params }) => {
  const post = await db.posts.findUnique({ where: { slug: params.slug } });
  if (!post) throw new Response('Not Found', { status: 404 });
  return json(post);
};

export default function Post() {
  const post = useLoaderData<typeof loader>();
  return <article><h1>{post.title}</h1><p>{post.content}</p></article>;
}
Enter fullscreen mode Exit fullscreen mode

Actions (Forms That Work)

export const action: ActionFunction = async ({ request }) => {
  const formData = await request.formData();
  const title = formData.get('title');
  const content = formData.get('content');

  await db.posts.create({ data: { title, content } });
  return redirect('/posts');
};

export default function NewPost() {
  return (
    <Form method="post">
      <input name="title" />
      <textarea name="content" />
      <button type="submit">Create</button>
    </Form>
  );
}
Enter fullscreen mode Exit fullscreen mode

This form works without JavaScript. Progressive enhancement built in.

Nested Routes

app/routes/
  dashboard.tsx         → /dashboard (layout)
  dashboard.settings.tsx → /dashboard/settings
  dashboard.analytics.tsx → /dashboard/analytics
Enter fullscreen mode Exit fullscreen mode

Each route loads its own data in parallel. Navigate between siblings — only the changed section re-renders.

Error Boundaries Per Route

export function ErrorBoundary() {
  const error = useRouteError();
  if (isRouteErrorResponse(error)) {
    return <div>{error.status}: {error.statusText}</div>;
  }
  return <div>Something went wrong</div>;
}
Enter fullscreen mode Exit fullscreen mode

An error in one section doesn't crash the whole page.

HTTP Caching

export const headers = () => ({
  'Cache-Control': 'public, max-age=300, s-maxage=3600',
});
Enter fullscreen mode Exit fullscreen mode

Standard HTTP headers. Works with every CDN.

Quick Start

npx create-remix@latest
cd my-remix-app
npm run dev
Enter fullscreen mode Exit fullscreen mode

Why This Matters

Web standards existed before React. Remix proves that embracing Request/Response and FormData makes apps simpler, faster, and more resilient.


Building data-driven Remix routes? Check out my web scraping actors on Apify Store — structured data for your loaders. For custom solutions, email spinov001@gmail.com.

Top comments (0)