
在 Next.js 13 的 App Router 中,客户端组件无法直接调用 redirect()(服务端专属),也不能在事件处理函数内调用 useRouter();正确做法是在组件顶层调用 useRouter,再于异步操作完成后使用 router.push() 实现前端跳转。
在 next.js 13 的 app router 中,客户端组件无法直接调用 `redirect()`(服务端专属),也不能在事件处理函数内调用 `userouter()`;正确做法是在组件顶层调用 `userouter`,再于异步操作完成后使用 `router.push()` 实现前端跳转。
在 Next.js 13+ 的混合渲染模型中,页面(如 page.tsx)默认为服务端组件(Server Component),而交互式 UI(如确认删除弹窗)必须封装为客户端组件(Client Component),并通过 "use client" 指令显式声明。此时,服务端重定向(如 redirect())不可用——它仅限服务端环境(如 page.tsx 或 "use server" 函数内),且会抛出 NEXT_REDIRECT 错误;而 useRouter() 是 React Client Component Hook,必须在组件顶层(而非事件回调内部)调用,否则触发 “Invalid hook call” 错误。
因此,正确的实现方式是:在 DeleteAddressAlertDialog 组件顶部调用 useRouter() 获取路由实例,并在 handleDelete 异步逻辑成功后调用 router.push() 进行客户端导航:
// DeleteAddressAlertDialog.tsx
"use client";
import { useRouter } from "next/navigation";
export default function DeleteAddressAlertDialog({
contactId,
addressId,
}: {
contactId: number;
addressId: number;
}) {
const router = useRouter(); // ✅ 正确:在组件顶层调用
const handleDelete = async () => {
try {
await deleteAddress(contactId, addressId);
router.push("/settings"); // ✅ 客户端跳转,无刷新(SPA 风格)
// 可选:添加 toast 提示或 setLoading(false)
} catch (error) {
console.error("删除地址失败:", error);
// 建议在此处反馈错误(如显示 Snackbar)
}
};
return (
<button onClick={handleDelete} className="text-red-600 hover:text-red-800">
删除地址
</button>
);
}⚠️ 注意事项:
- 必须在组件文件首行添加 "use client",否则 useRouter 将不可用;
- router.push() 不会触发完整页面刷新,而是利用 Next.js 的客户端导航机制跳转,体验更流畅;
- 若需强制硬跳转(例如清除状态),可使用 router.replace("/settings") 或原生 window.location.href = "/settings"(不推荐,破坏 SPA 体验);
- deleteAddress 已正确定义为 "use server" 函数,确保敏感操作(如 API 调用、认证)在服务端执行,符合安全最佳实践;
- 实际项目中建议配合加载状态(如 useState 控制按钮禁用)与错误提示,提升用户体验。
总结:Next.js 13 中的重定向需严格区分服务端与客户端上下文——服务端用 redirect(),客户端用 useRouter().push(),且 Hook 调用位置必须合规。这是 App Router 架构下数据操作与导航解耦的标准范式。


















