I have the following Form component which receives the input fields as a children prop:
return (<form action={dispatch} className="w-full flex" autoComplete="off"><div className={`${fieldSpacing} ${maxWidthClass} w-full`}> {React.Children.map(children, (child) => { if (React.isValidElement(child)) { const isCustomComponent = typeof child.type !== "string"; const childProps = isCustomComponent ? { ...child.props, errors: errors[child.props.name], formState, } : { ...child.props, }; return React.cloneElement(child, childProps); } return child; })} {notification && <Notification {...notification} />}</div></form> );
That currently works well but I need to delay the submission to make some animations in the form before the data is sent to the server. Then I've modified the code to:
const handleAction = (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); const formData = new FormData(event.currentTarget); dispatch(formData); }; return (<form //action={dispatch} onSubmit={handleAction} className="w-full flex" autoComplete="off"><div className={`${fieldSpacing} ${maxWidthClass} w-full`}> {React.Children.map(children, (child) => { if (React.isValidElement(child)) { const isCustomComponent = typeof child.type !== "string"; const childProps = isCustomComponent ? { ...child.props, errors: errors[child.props.name], formState, } : { ...child.props, }; return React.cloneElement(child, childProps); } return child; })} {notification && <Notification {...notification} />}</div></form> );
This also works, sending the data to the server but the problem is that I cannot automatically get the pending
state (from useFormStatus
) on my submit button component anymore (it works using the action in the first version of the code).
This is my button component (submit):
const Button: React.FC<Props> = ({ title, bgColor, href, ...buttonProps }) => { const { pending } = useFormStatus(); const bgColorClass = bgColor === "purple" ? "bg-purple-900 hover:bg-purple-950 border-purple-950 disabled:bg-purple-950 disabled:border-purple-950" : "bg-indigo-800 hover:bg-indigo-900 border-indigo-900 disabled:bg-indigo-900 disabled:border-indigo-900"; const isSubmitLoading = buttonProps.type === "submit" && pending; // Text animation variants const textVariants = { initial: { y: 0, opacity: 1 }, hidden: { y: -20, opacity: 0 }, }; // Spinner animation variants const spinnerVariants = { initial: { y: 20, opacity: 0 }, visible: { y: 0, opacity: 1 }, }; const ButtonContent = (<> {!isSubmitLoading && (<motion.div initial="initial" animate={isSubmitLoading ? "hidden" : "initial"} variants={textVariants} transition={{ duration: 0.2 }}> {title}</motion.div> )} {isSubmitLoading && (<motion.div initial="initial" animate={isSubmitLoading ? "visible" : "hidden"} exit={{ opacity: 0 }} variants={spinnerVariants} transition={{ duration: 0.2 }}><LiaSpinnerSolid className="animate-spin text-xl" /></motion.div> )}</> ); return (<div className="w-full"> {href ? (<Link href={href} className={`inline-flex items-center justify-center border rounded-md py-2 px-4 text-sm font-bold text-gray-100 shadow-sm transition-all duration-200 w-full uppercase ${bgColorClass}`}> {ButtonContent}</Link> ) : (<button {...buttonProps} className={`inline-flex items-center justify-center border rounded-md py-2 px-4 text-sm font-bold text-gray-100 shadow-sm transition-all duration-200 w-full uppercase disabled:cursor-not-allowed ${bgColorClass}`} disabled={buttonProps.disabled || pending}> {ButtonContent}</button> )}</div> );};
How can I fix it? Is the only option to create a global state for this? I'd like to get the this to work using the pending
state if possible.
Thank you!