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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions