Passing 'props' to children component and conditionally render it

51 Views Asked by At

It's my loginButton which is the wrapper of Button component in another file.

'use client';

import { useRouter } from 'next/navigation';
import { useTransition } from 'react';

interface LoginButtonProps {
  children: React.ReactNode;
  mode?: 'modal' | 'redirect';
  asChild?: boolean;
}

export const LoginButton = ({
  children,
  mode = 'redirect',
  asChild,
}: LoginButtonProps) => {
  const router = useRouter();
  const [isPending, startTransition] = useTransition();

  const onclickHandler = () => {
    router.push('/auth/login');
    console.log('clicked');
  };

  return (
    <span className="cursor-pointer" onClick={onclickHandler}>
      {children}
    </span>
  );
};

and the Button component is:

import { Button } from '@/components/ui/button';
import { LoginButton } from '@/components/auth/login-button';

export default function Home() {
  return (
    <main>
        <LoginButton>
          <Button variant="secondary" size="lg" className="mt-8">
            Sign in
          </Button>
        </LoginButton>
      </div>
    </main>
  );
}

I want to pass the isPending state as prop and use inside Home component. I want to keep the button disabled while isPending is true as well as change its text. how to achieve this?

Please help me with your valuable time and knowledge. Thanks in advance.

2

There are 2 best solutions below

1
Chinz On BEST ANSWER

You can try passing a fallback component to the LoginButton that will be rendered while the transition is pending.

Login Button:

export const LoginButton = ({
  children,
  mode = 'redirect',
  asChild,
  fallback
}: LoginButtonProps) => {
  const router = useRouter();
  const [isPending, startTransition] = useTransition();

  const onclickHandler = () => {
    router.push('/auth/login');
    console.log('clicked');
  };

  return (
    <span className="cursor-pointer" onClick={onclickHandler}>
      {isPending ? fallback : children}
    </span>
  );
};

Fallback Component:

function LoadingBtn() {
 return (
   <Button variant="secondary" size="lg" className="mt-8" disabled>
      Loading
   </Button>
 )
}

Implementation:

<LoginButton fallback={<LoadingBtn />}>
          <Button variant="secondary" size="lg" className="mt-8">
            Sign in
          </Button>
</LoginButton>
0
Olivier Boissé On

You can pass a function (instead of a react element) as children of LoginButton

export default function Home() {
  return (
    <main>
        <LoginButton>
          {disabled => ( 
            <Button 
              variant="secondary" 
              size="lg" 
              className="mt-8" 
              disabled={disabled}
            >
              Sign in
            </Button>
          )}
        </LoginButton>
      </div>
    </main>
  );
}

and call this function in LoginButton component


export const LoginButton = ({children}) => {
  const [isPending, startTransition] = useTransition();

  ...  

  return (
    <span className="cursor-pointer" onClick={onclickHandler}>
      {children(isPending)}
    </span>
  );
};