You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将LoginButton的isPending状态传递给Home组件并控制按钮状态?

解决方案

有两种常用方式可以实现将isPending状态传递给父组件Home,从而控制按钮的禁用状态和文本:

方案一:使用Render Props(子组件向父组件传递状态)

修改LoginButton组件,允许children作为接收isPending状态的函数,让父组件直接拿到该状态并控制按钮:

'use client';

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

// 更新Props接口,支持children为函数
interface LoginButtonProps {
  children: React.ReactNode | ((isPending: boolean) => React.ReactNode);
  mode?: 'modal' | 'redirect';
  asChild?: boolean;
}

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

  const onclickHandler = () => {
    // 用startTransition包裹路由跳转,确保isPending状态正确触发
    startTransition(() => {
      router.push('/auth/login');
    });
    console.log('clicked');
  };

  // 判断children是否为函数,是则传入isPending调用
  const renderedChildren = typeof children === 'function'
    ? children(isPending)
    : children;

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

在Home组件中,通过函数形式的children接收isPending,并控制按钮:

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

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

方案二:状态提升到父组件

将useTransition的状态逻辑移到Home组件,把isPending和startTransition作为props传递给LoginButton:

首先修改LoginButton的Props接口:

'use client';

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

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

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

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

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

在Home组件中管理状态并传递:

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

export default function Home() {
  const [isPending, startTransition] = useTransition();

  return (
    <main>
      <LoginButton isPending={isPending} startTransition={startTransition}>
        <Button 
          variant="secondary" 
          size="lg" 
          className="mt-8"
          disabled={isPending}
        >
          {isPending ? 'Signing in...' : 'Sign in'}
        </Button>
      </LoginButton>
    </main>
  );
}

注意事项

  • 两种方案都需要确保路由跳转被startTransition包裹,这样isPending状态才会正确触发(原代码中router.push未被包裹,isPending可能不会生效)。
  • 如果LoginButton在多个地方复用,方案一(Render Props)更灵活,无需每个父组件都管理状态;方案二更适合需要在父组件中对isPending做额外逻辑处理的场景。

内容的提问来源于stack exchange,提问作者Samiul Islam Shibly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 01:55:25