All skills
sergiodxa avatar

/frontend-react-router-best-practices

@9da9532

React Router performance and architecture patterns. Use when writing loaders, actions, forms, routes, or working with React Router data fetching. Triggers on tasks involving React Router routes, data loading, form handling, or route organization.

Use this Skill: https://skilld.dev/gh/sergiodxa/agent-skills/frontend-react-router-best-practices

This session only. Nothing lands on disk.

rulesprefetch-fetcher-data.md

≈1.1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Prefetch Data for Fetcher Usage

Use <PrefetchPageLinks> to preload data for routes that will be loaded via fetcher.load().

Why

  • <Link prefetch="intent"> only works for navigation, not fetcher calls
  • Modals, drawers, and expandable sections often load data on demand
  • Preloading this data improves perceived performance
  • Data is ready when the user clicks, making the UI feel instant

The Problem

When using fetcher.load() to load data (e.g., for a modal), the data fetch only starts when the user triggers the action:

function ItemDetails({ itemId }: { itemId: string }) {
  let fetcher = useFetcher<typeof resourceLoader>();

  return (
    <>
      <button onClick={() => fetcher.load(`/api/items/${itemId}`)}>
        View Details
      </button>
      {fetcher.data && <Modal data={fetcher.data} />}
    </>
  );
}

The user clicks, waits for data to load, then sees the modal.

Solution: PrefetchPageLinks

Render <PrefetchPageLinks> to start preloading the data immediately:

import { useFetcher, PrefetchPageLinks } from "react-router";

function ItemDetails({ itemId }: { itemId: string }) {
  let fetcher = useFetcher<typeof resourceLoader>();

  return (
    <>
      {/* Preload data for this resource route */}
      <PrefetchPageLinks page={`/api/items/${itemId}`} />

      <button onClick={() => fetcher.load(`/api/items/${itemId}`)}>
        View Details
      </button>
      {fetcher.data && <Modal data={fetcher.data} />}
    </>
  );
}

When the component renders, it starts prefetching. By the time the user clicks, data may already be cached.

How It Works

<PrefetchPageLinks> renders <link rel="prefetch"> tags in the document head:

<link
  rel="prefetch"
  as="fetch"
  href="/api/items/123?_data=routes/api.items.$itemId"
/>

The browser prefetches the data in the background. When fetcher.load() is called, it uses the cached response.

Use Cases

Modal Data Preloading

function UserRow({ user }: { user: User }) {
  let [isOpen, setIsOpen] = useState(false);
  let fetcher = useFetcher<typeof userDetailsLoader>();

  return (
    <tr>
      <PrefetchPageLinks page={`/api/users/${user.id}/details`} />
      <td>{user.name}</td>
      <td>
        <button
          onClick={() => {
            fetcher.load(`/api/users/${user.id}/details`);
            setIsOpen(true);
          }}
        >
          View Profile
        </button>
      </td>
      {isOpen && fetcher.data && (
        <UserProfileModal
          user={fetcher.data}
          onClose={() => setIsOpen(false)}
        />
      )}
    </tr>
  );
}

Expandable Sections

function AccordionItem({ sectionId, title }: Props) {
  let [isExpanded, setIsExpanded] = useState(false);
  let fetcher = useFetcher<typeof sectionLoader>();

  return (
    <div>
      <PrefetchPageLinks page={`/api/sections/${sectionId}`} />
      <button
        onClick={() => {
          if (!fetcher.data) fetcher.load(`/api/sections/${sectionId}`);
          setIsExpanded((isExpanded) => !isExpanded);
        }}
      >
        {title}
      </button>
      {isExpanded && fetcher.data && <div>{fetcher.data.content}</div>}
    </div>
  );
}

Conditional Prefetching

Only prefetch when likely to be used:

function ItemCard({ item, isHovered }: Props) {
  let fetcher = useFetcher<typeof detailsLoader>();

  return (
    <div>
      {/* Only prefetch when user hovers */}
      {isHovered && <PrefetchPageLinks page={`/api/items/${item.id}`} />}
      <button onClick={() => fetcher.load(`/api/items/${item.id}`)}>
        Details
      </button>
    </div>
  );
}

When to Use

Scenario Use
Navigation to another page <Link prefetch="intent">
Modal/drawer data loading <PrefetchPageLinks>
Expandable section content <PrefetchPageLinks>
Data loaded on button click <PrefetchPageLinks>

Rules

  1. Use <PrefetchPageLinks page="/path"> for fetcher.load() prefetching
  2. Use <Link prefetch="intent"> for navigation prefetching
  3. Consider conditional rendering to avoid prefetching data that won't be used
  4. The page prop should match the URL passed to fetcher.load()
  5. Works with resource routes that export a loader

Source: SKILL.md on GitHub

2 warnings16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill provides a comprehensive set of developer guidelines and best practices for building React Router applications. It emphasizes performance, type safety, and security measures like input validation (Zod), safe redirects, and CSRF protection (Sec-Fetch). No malicious code, obfuscation, or data exfiltration patterns were detected.

  • Socket16d

    1 alert: gptSecurity

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    56/56 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 9da9532. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Dormantupdated 8 months ago

README badge

README badge for sergiodxa/agent-skills/frontend-react-router-best-practices