Skip to content

Potentially simpler Link wrapper implementation? #14

@musjj

Description

@musjj

I was playing around with my own progress bar implementation while referencing this library, and I discovered that you don't actually have to call startProgress in the same callback with the task you're trying to track:

"use client";

import NextLink from "next/link";
import {
  type ComponentPropsWithoutRef,
  forwardRef,
  startTransition,
} from "react";
import { useProgress } from "react-transition-progress";

export const Link = forwardRef<
  HTMLAnchorElement,
  ComponentPropsWithoutRef<typeof NextLink>
>(({ onClick, ...props }, ref) => {
  const startProgress = useProgress();

  return (
    <NextLink
      ref={ref}
      onClick={(e) => {
        onClick?.(e);
        startTransition(startProgress);
      }}
      {...props}
    />
  );
});

Link.displayName = "Link";

I have no idea why this even works though. I tested it with heavy network throttling and everything seems perfectly sound.

If this is actually a good approach, it would eliminate the need to duplicate Link's logic (like the current URL formatter).

Would appreciate more eyes on this though (and maybe an explanation too).

EDIT: Also works for submit buttons in server action forms:

button.tsx

"use client";

export const Button = forwardRef<
  HTMLButtonElement,
  ComponentPropsWithoutRef<"button">
>(({ onClick, ...props }, ref) => {
  const startProgress = useProgress();

  return (
    <button
      ref={ref}
      onClick={(e) => {
        onClick?.(e);
        startTransition(startProgress);
      }}
      {...props}
    />
  );
});

Button.displayName = "Button";

page.tsx

export default function Page() {
  return (
    <form
      action={async () => {
        "use server";
        // Play with the timeout value below to test if progress bar is accurate
        await new Promise((r) => setTimeout(r, 7000));
      }}
    >
      <Button type="submit">Submit!</Button>
    </form>
  );
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions