CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-remix-run--react

React DOM bindings for Remix web framework providing components, hooks, and utilities for full-stack React applications

Pending
Overview
Eval results
Files

data-response-utilities.mddocs/

Data Response Utilities

Server runtime utilities for creating responses, redirects, and handling deferred data in Remix loader and action functions.

Capabilities

JSON Response

Create JSON responses with proper headers and serialization.

/**
 * Creates a Response with JSON data and appropriate headers
 * Automatically serializes data and sets Content-Type header
 * @param data - Data to serialize as JSON
 * @param init - Optional response initialization options
 * @returns Response object with JSON data
 */
function json<Data>(data: Data, init?: ResponseInit): Response;

Usage Examples:

import { json } from "@remix-run/react";
import type { LoaderFunctionArgs } from "@remix-run/node";

// Basic JSON response
export async function loader({ params }: LoaderFunctionArgs) {
  const user = await getUser(params.userId);
  
  if (!user) {
    throw json({ error: "User not found" }, { status: 404 });
  }
  
  return json({
    user,
    lastUpdated: new Date(),
    preferences: user.preferences,
  });
}

// JSON response with custom headers
export async function loader() {
  const data = await getPublicData();
  
  return json(data, {
    headers: {
      "Cache-Control": "public, max-age=3600",
      "X-Custom-Header": "value",
    },
  });
}

// JSON error response
export async function action({ request }: ActionFunctionArgs) {
  const formData = await request.formData();
  
  try {
    const result = await processForm(formData);
    return json({ success: true, result });
  } catch (error) {
    return json(
      { 
        success: false, 
        error: error.message,
        field: "email" 
      },
      { status: 400 }
    );
  }
}

Redirect Response

Create redirect responses for navigation and flow control.

/**
 * Creates a redirect Response to the specified URL
 * @param url - URL to redirect to
 * @param init - Optional response initialization options
 * @returns Response object with redirect status and Location header
 */
function redirect(url: string, init?: ResponseInit): Response;

/**
 * Creates a redirect Response that reloads the entire document
 * Forces a full page reload instead of client-side navigation
 * @param url - URL to redirect to
 * @param init - Optional response initialization options
 * @returns Response object with redirect and document reload
 */
function redirectDocument(url: string, init?: ResponseInit): Response;

/**
 * Creates a redirect Response that replaces the current entry in the history stack
 * Uses replace navigation instead of pushing a new entry
 * @param url - URL to redirect to
 * @param init - Optional response initialization options (defaults to 302)
 * @returns Response object with redirect status and Location header
 */
function replace(url: string, init?: ResponseInit): Response;

Usage Examples:

import { redirect, redirectDocument, replace } from "@remix-run/react";
import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node";

// Basic redirect
export async function loader({ request }: LoaderFunctionArgs) {
  const user = await getCurrentUser(request);
  
  if (!user) {
    return redirect("/login");
  }
  
  return json({ user });
}

// Redirect with custom status
export async function action({ request }: ActionFunctionArgs) {
  const formData = await request.formData();
  const result = await createPost(formData);
  
  // Redirect to the new post with 201 status
  return redirect(`/posts/${result.id}`, { status: 201 });
}

// Document redirect (full page reload)
export async function action({ request }: ActionFunctionArgs) {
  await processPayment(request);
  
  // Force full page reload for payment confirmation
  return redirectDocument("/payment/success");
}

// Replace redirect (replaces current history entry)
export async function action({ request }: ActionFunctionArgs) {
  const formData = await request.formData();
  const result = await updateProfile(formData);
  
  // Replace current URL instead of adding to history
  return replace("/profile", { status: 302 });
}

// Conditional redirect
export async function loader({ request, params }: LoaderFunctionArgs) {
  const user = await getCurrentUser(request);
  const post = await getPost(params.postId);
  
  if (!post) {
    throw json({ error: "Post not found" }, { status: 404 });
  }
  
  if (post.private && post.authorId !== user?.id) {
    return redirect("/unauthorized");
  }
  
  return json({ post, user });
}

Deferred Response

Create responses with deferred data for streaming and progressive loading.

/**
 * Creates a Response with deferred data for streaming
 * Allows some data to load immediately while other data streams in later
 * @param data - Object containing immediate and deferred data
 * @param init - Optional response initialization options
 * @returns Response object with streaming deferred data
 */
function defer<Data extends Record<string, unknown>>(
  data: Data,
  init?: ResponseInit
): Response;

Usage Examples:

import { defer, json } from "@remix-run/react";
import { Await, useLoaderData } from "@remix-run/react";
import { Suspense } from "react";
import type { LoaderFunctionArgs } from "@remix-run/node";

// Deferred data loading
export async function loader({ params }: LoaderFunctionArgs) {
  const user = await getUser(params.userId); // Fast query
  
  // Defer slow queries
  const posts = getUserPosts(params.userId); // Don't await
  const analytics = getUserAnalytics(params.userId); // Don't await
  
  return defer({
    user, // Immediate data
    posts, // Deferred promise
    analytics, // Deferred promise
  });
}

// Component using deferred data
export default function UserProfile() {
  const { user, posts, analytics } = useLoaderData<typeof loader>();
  
  return (
    <div>
      <h1>{user.name}</h1>
      
      <Suspense fallback={<div>Loading posts...</div>}>
        <Await resolve={posts}>
          {(resolvedPosts) => (
            <PostsList posts={resolvedPosts} />
          )}
        </Await>
      </Suspense>
      
      <Suspense fallback={<div>Loading analytics...</div>}>
        <Await resolve={analytics}>
          {(resolvedAnalytics) => (
            <AnalyticsDashboard data={resolvedAnalytics} />
          )}
        </Await>
      </Suspense>
    </div>
  );
}

// Mixed immediate and deferred data
export async function loader() {
  const criticalData = await getCriticalData(); // Must load first
  const slowData = getSlowData(); // Defer this
  
  return defer({
    critical: criticalData,
    slow: slowData,
    metadata: { loadTime: Date.now() },
  });
}

Replace Response

Create responses that replace the current history entry.

/**
 * Creates a response that replaces the current history entry
 * Useful for preventing back button navigation to intermediate states
 * @param url - URL to replace with
 * @param init - Optional response initialization options
 * @returns Response object with replace behavior
 */
function replace(url: string, init?: ResponseInit): Response;

Usage Examples:

import { replace, json } from "@remix-run/react";
import type { ActionFunctionArgs } from "@remix-run/node";

// Replace after form submission
export async function action({ request }: ActionFunctionArgs) {
  const formData = await request.formData();
  
  if (formData.get("step") === "confirm") {
    await processOrder(formData);
    // Replace the confirmation step in history
    return replace("/order/success");
  }
  
  return json({ step: "confirm" });
}

Generic Data Response

Create flexible data responses for various content types.

/**
 * Creates a generic data response with flexible content handling
 * Supports various data types and custom serialization
 * @param data - Data to include in the response
 * @param init - Optional response initialization options
 * @returns Response object with the provided data
 */
function data<Data>(data: Data, init?: ResponseInit): Response;

Usage Examples:

import { data } from "@remix-run/react";

// Custom response with specific content type
export async function loader() {
  const csvData = await generateCSVReport();
  
  return data(csvData, {
    headers: {
      "Content-Type": "text/csv",
      "Content-Disposition": "attachment; filename=report.csv",
    },
  });
}

// Binary data response
export async function loader({ params }: LoaderFunctionArgs) {
  const imageBuffer = await getImage(params.imageId);
  
  return data(imageBuffer, {
    headers: {
      "Content-Type": "image/jpeg",
      "Cache-Control": "public, max-age=86400",
    },
  });
}

Type Definitions

Response Initialization

interface ResponseInit {
  /** HTTP status code */
  status?: number;
  /** HTTP status text */
  statusText?: string;
  /** Response headers */
  headers?: HeadersInit;
}

type HeadersInit = Headers | string[][] | Record<string, string>;

Deferred Data Type

/**
 * Type for deferred data objects
 * Keys can contain immediate values or promises that resolve later
 */
type DeferredData<T extends Record<string, unknown>> = {
  [K in keyof T]: T[K] | Promise<T[K]>;
};

Implementation Notes

  • Streaming: Deferred responses enable streaming data to the client as it becomes available
  • Performance: Immediate data renders instantly while slow queries complete in the background
  • Error Handling: Deferred promises can reject and be caught by error boundaries
  • SEO: Search engines receive immediate data for indexing while deferred data loads progressively
  • Type Safety: All response utilities maintain full TypeScript type safety
  • Headers: Custom headers can be set for caching, content type, and security policies
  • Status Codes: HTTP status codes can be customized for proper REST API compliance

Install with Tessl CLI

npx tessl i tessl/npm-remix-run--react

docs

application-entry-points.md

data-loading-hooks.md

data-response-utilities.md

document-components.md

forms-and-navigation.md

index.md

react-router-integration.md

type-definitions.md

tile.json