Next.js Discord

Discord Forum

How to load until after router ends executing?

Unanswered
Buff-collared Nightjar posted this in #help-forum
Open in Discord
Buff-collared NightjarOP
Aim:
I have a button that should start "loading spinner" when the user clicks on the button, and should stop the loading spinner when the page that the router takes mounts.

Environment:
- Nextjs v14
- App router

My attempt:
'use client';

import { useState } from 'react';
import { Button, ButtonProps } from './ui/button';
import { useRouter } from 'next/navigation';

interface ButtonWithLinkProcessingProps extends ButtonProps {
  href: string;
  children: React.ReactNode;
}

export function ButtonWithLinkProcessing({
  href,
  children,
  ...props
}: ButtonWithLinkProcessingProps) {
  const [isProcessing, setIsProcessing] = useState(false);
  const router = useRouter();

  return (
    <Button
      onClick={async (e) => {
        e.preventDefault();
        setIsProcessing(true);
        await router.push(href);
        setIsProcessing(false);
      }}
      isProcessing={isProcessing}
      {...props}
    >
      {children}
    </Button>
  );
}


Current result: When the user clicks on the button, then the router jumps to the page, and the button never enters the "processing" state.

4 Replies

Buff-collared NightjarOP
when I remove setIsProcessing(false);, then I get the expected result. However, removing that function call also creates some unexpected behaviour (e.g., never ending spinner)
Buff-collared NightjarOP
i solved it by using "useTransition" hook
'use client';

import { useTransition } from 'react';
import { Button, ButtonProps } from './ui/button';
import { useRouter } from 'next/navigation';

interface ButtonWithLinkProcessingProps extends ButtonProps {
  href: string;
  children: React.ReactNode;
}

export function ButtonWithLinkProcessing({
  href,
  children,
  ...props
}: ButtonWithLinkProcessingProps) {
  const [isProcessing, startTransition] = useTransition();
  const router = useRouter();

  return (
    <Button
      onClick={(e) => {
        e.preventDefault();
        startTransition(() => {
          router.push(href);
        });
      }}
      isProcessing={isProcessing}
      {...props}
    >
      {children}
    </Button>
  );
}