表单操作/服务器操作导致SSR页面中的提取重新触发

问题描述 投票:0回答:1

我试图了解我们在 Next.js 应用程序 v.14(应用程序路由器)中遇到的问题。

我们有一个 SSR 页面,它首先通过调用验证令牌端点来验证 JWT 令牌。如果令牌有效,我们会在此页面上呈现一个表单(use-client 指令)。该表单使用客户端操作来验证用户输入。验证成功后,它会触发服务器端操作,该操作与 API 通信以注册用户。

我们看到的问题是,成功提交表单后,会再次调用 verifySignupToken。由于我们在使用 router.push 提交表单后进行客户端导航,我们应该直接跳到新路线吗?我不确定为什么它会在父组件中再次重新触发 fetch 调用?

SSR 页面(带有强制动态配置选项):

export const dynamic = 'force-dynamic'

export default async function Signup({ searchParams }: SignUpProps) {
  const { token, customerId, email } = searchParams

  const result = safeParse(VerifySignupSchema, { token, email, customerId })

  if (!result.success) {
    console.error(result.issues)
    redirect('/login?error=validation')
  }

  const validatedData = result.output

  try {
    await verifySignupToken(validatedData.token, validatedData.customerId, validatedData.email)
  } catch (error) {
    if (error instanceof Error) {
      redirect(`/login?error=${encodeURIComponent(error.message)}`)
    }
  }

  return (
    <SignUpForm
      token={validatedData.token}
      customerId={validatedData.customerId}
      email={validatedData.email}
    />
  )
}

SignUpForm(使用客户端指令,客户端操作调用服务器端操作):

export const SignUpForm = ({ token, customerId, email }: SignUpFormProps) => {
  const router = useRouter()
  const { pending } = useFormStatus()

  const signUpClientAction = async (formData: FormData) => {
    const password = formData.get('password')
    const pnr = formData.get('pnr')

    const result = safeParse(SignUpSchema, { password, pnr })

    if (!result.success) {
      toast.error(result.issues[0].message)
      return
    }

    const validatedData = result.output

    const response = await signupAction(
      email,
      validatedData.password,
      token,
      validatedData.pnr,
      customerId
    )

    if (response.success) {
      toast.success(response.message)
      router.push('/')
    } else if (response.statusCode === 401) {
      toast.error(response.message)
      router.push('/login')
    } else {
      toast.error(response.message)
    }
  }

  return (
    <div className="mt-10">
      <div>
        <form className="space-y-6" action={signUpClientAction}>
    ....

next.js
1个回答
0
投票

在 next.js 13 之前,next.js 有

shallow routing
,这是一种允许您更新页面 URL 的技术,而无需重新加载页面本身或从服务器获取新数据。

来自 shallow-routing-with-next-js-v13-app-directory-

在 Next.js v13 中,总是添加或删除搜索参数 触发硬重载。相比之下,Next.js v12 允许命令 像 router.push('/?counter=10', undefined, {shallow: true }) 一样 在不启动硬重新加载的情况下执行。不幸的是,在 当前版本,类似的代码总是会导致硬重新加载,从而导致 所有组件都需要重新渲染,即使是同一页面。

解决方案

当新实现的应用程序面临此类限制时,重新访问 Web API 总是一个好主意。我们的 这里的目标是找到一种无需立即修改 URL 的方法 触发整页重新加载。

实现此目的的一种流行方法是使用 “window.history.pushState()”。

现在我需要监听另一个 URL 的变化 成分。那么让我们编写一个钩子来为我们做到这一点。

import { useEffect } from 'react';

export const usePushStateListener = (callback) => {
  useEffect(() => {
     // make a copy of original function to avoid complications
    const originalPushState = history.pushState;

    history.pushState = function (data, title, url) {
      originalPushState.apply(history, [data, title, url]);
      callback(url); 

    return () => {
      history.pushState = originalPushState; // restore the copy
    };
  }, [callback]);
};

当在任何情况下调用“window.history.pushState”方法时 组件中定义的重写的“pushState”方法 “usePushStateListener”钩子将被执行。这允许钩子 监听 URL 变化并触发更新后的回调函数 网址。

© www.soinside.com 2019 - 2024. All rights reserved.