NextJS中如何在客户端组件内嵌套Dialog、Drawer并传参
可行,而且这是优化重复代码的好方案
完全可以在同一个Form.jsx客户端组件内嵌套Dialog、Drawer、AlertDialog等组件,并向它们传递open、setOpen这类状态变量。同时还可以通过抽离重复的表单内容来消除代码冗余,具体实现步骤如下:
1. 抽离重复的表单内容为独立子组件
把重复的表单字段、提交逻辑抽成一个可复用的子组件,避免在Dialog和Drawer中重复写相同代码:
const FormContent = ({ onSubmit }) => { return ( <form onSubmit={onSubmit} className="space-y-4 p-4"> {/* 表单字段示例,替换成你的实际内容 */} <div> <label htmlFor="username" className="block text-sm font-medium mb-1">用户名</label> <input type="text" id="username" className="w-full p-2 border rounded-md" placeholder="请输入用户名" /> </div> <div> <label htmlFor="email" className="block text-sm font-medium mb-1">邮箱</label> <input type="email" id="email" className="w-full p-2 border rounded-md" placeholder="请输入邮箱" /> </div> <div className="flex justify-end"> <button type="submit" className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700" > 提交表单 </button> </div> </form> ); };
2. 在主组件中嵌套Dialog、Drawer并传递状态
在Form.jsx(记得加'use client'指令,这是NextJS客户端组件的要求)中,用useState管理各弹窗的显示状态,根据设备类型渲染Dialog或Drawer,并将状态变量传递给它们:
'use client'; import { useState, useMediaQuery } from 'react'; // 这里假设你用的是自定义或第三方组件库的弹窗组件,可根据实际情况替换 import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog'; import { Drawer, DrawerContent, DrawerTrigger } from '@/components/ui/drawer'; import { AlertDialog, AlertDialogContent } from '@/components/ui/alert-dialog'; const Form = () => { // 管理各弹窗的显示状态 const [dialogOpen, setDialogOpen] = useState(false); const [drawerOpen, setDrawerOpen] = useState(false); const [alertOpen, setAlertOpen] = useState(false); // 判断是否为桌面端(可根据需求调整断点) const isDesktop = useMediaQuery('(min-width: 768px)'); // 表单提交逻辑 const handleSubmit = (e) => { e.preventDefault(); // 这里添加你的表单验证、提交逻辑 setAlertOpen(true); // 提交后打开提示弹窗 // 关闭当前的Dialog/Drawer isDesktop ? setDialogOpen(false) : setDrawerOpen(false); }; return ( <div className="p-4"> {/* 根据设备类型渲染Dialog或Drawer */} {isDesktop ? ( <Dialog open={dialogOpen} onOpenChange={setDialogOpen}> <DialogTrigger asChild> <button className="px-4 py-2 bg-gray-200 rounded-md hover:bg-gray-300"> 打开桌面端表单 </button> </DialogTrigger> <DialogContent className="sm:max-w-md"> <FormContent onSubmit={handleSubmit} /> </DialogContent> </Dialog> ) : ( <Drawer open={drawerOpen} onOpenChange={setDrawerOpen}> <DrawerTrigger asChild> <button className="px-4 py-2 bg-gray-200 rounded-md hover:bg-gray-300"> 打开移动端表单 </button> </DrawerTrigger> <DrawerContent> <FormContent onSubmit={handleSubmit} /> </DrawerContent> </Drawer> )} {/* 嵌套的AlertDialog,用于提交成功提示 */} <AlertDialog open={alertOpen} onOpenChange={setAlertOpen}> <AlertDialogContent> <h3 className="text-lg font-semibold mb-2">提交成功!</h3> <p className="text-sm text-gray-600 mb-4">你的表单已成功提交,我们会尽快处理。</p> <button onClick={() => setAlertOpen(false)} className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700" > 确认 </button> </AlertDialogContent> </AlertDialog> </div> ); }; // 抽离的表单内容组件 const FormContent = ({ onSubmit }) => { return ( <form onSubmit={onSubmit} className="space-y-4 p-4"> {/* 表单字段示例,替换成你的实际内容 */} <div> <label htmlFor="username" className="block text-sm font-medium mb-1">用户名</label> <input type="text" id="username" className="w-full p-2 border rounded-md" placeholder="请输入用户名" /> </div> <div> <label htmlFor="email" className="block text-sm font-medium mb-1">邮箱</label> <input type="email" id="email" className="w-full p-2 border rounded-md" placeholder="请输入邮箱" /> </div> <div className="flex justify-end"> <button type="submit" className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700" > 提交表单 </button> </div> </form> ); }; export default Form;
关键注意点
- 必须在客户端组件顶部添加
'use client'指令,NextJS 13+的App Router中只有带这个指令的组件才能使用React状态、钩子等客户端特性。 - 传递状态变量时,直接将
open和onOpenChange(或setOpen,取决于组件的API)作为props传给Dialog/Drawer组件即可,组件内部会根据这些值控制显示状态。 - 抽离
FormContent组件不仅消除了重复代码,还让表单逻辑更集中,后续修改表单只需要改这一个地方。
内容的提问来源于stack exchange,提问作者NicoCaldo
相关产品推荐
相关产品推荐

