如何将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
相关产品推荐
相关产品推荐

