You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js13+Chakra UI中用react-hook-form跳转至确认页

解决方案

针对你用Next.js13、Chakra UI和react-hook-form开发的跨页面表单需求,以下是几种无需查询参数的实现方案:


方案1:React Context + 客户端跳转(适合无刷新客户端场景)

通过React Context临时存储表单数据,客户端跳转后读取,适合不需要持久化数据的场景。

1. 创建表单数据Context

// app/context/FormDataContext.tsx
'use client';

import { createContext, useContext, useState, ReactNode } from 'react';

type FormDataContextType = {
  formData: { email?: string };
  setFormData: (data: { email?: string }) => void;
};

const FormDataContext = createContext<FormDataContextType | undefined>(undefined);

export function FormDataProvider({ children }: { children: ReactNode }) {
  const [formData, setFormData] = useState<{ email?: string }>({});

  return (
    <FormDataContext.Provider value={{ formData, setFormData }}>
      {children}
    </FormDataContext.Provider>
  );
}

export function useFormData() {
  const context = useContext(FormDataContext);
  if (!context) {
    throw new Error('useFormData必须在FormDataProvider内使用');
  }
  return context;
}

2. 在根布局中注入Provider

// app/layout.tsx
import { FormDataProvider } from './context/FormDataContext';

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="zh-CN">
      <body>
        <FormDataProvider>{children}</FormDataProvider>
      </body>
    </html>
  );
}

3. 修改NewForm组件提交逻辑

'use client';

import { useForm } from 'react-hook-form';
import { Box, FormControl, Input, Button, Text } from '@chakra-ui/react';
import { useRouter } from 'next/navigation';
import { useFormData } from '../context/FormDataContext';

type NewFormType = { email: string };

export const NewForm = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<NewFormType>();
  const router = useRouter();
  const { setFormData } = useFormData();

  const onSubmit = handleSubmit((data) => {
    setFormData(data);
    router.push('/xxx/confirm');
  });

  return (
    <Box p={4}>
      <form onSubmit={onSubmit}>                      
        <FormControl isInvalid={!!errors.email} mb={4}>
          <Input
            id="email"
            type="email"
            placeholder="请输入邮箱"
            {...register("email", { required: "邮箱不能为空" })}
          />
          {errors.email && <Text color="red.500" mt={1}>{errors.email.message}</Text>}
        </FormControl>
        <Button type="submit" colorScheme="blue">Confirm</Button>
      </form>
    </Box>
  );
};

4. 确认页面读取数据

'use client';

import { Box, Heading, Text } from '@chakra-ui/react';
import { useFormData } from '../context/FormDataContext';

export default function ConfirmPage() {
  const { formData } = useFormData();

  if (!formData.email) {
    return <Box p={4}>请先填写表单</Box>;
  }

  return (
    <Box p={4}>
      <Heading size="md" mb={4}>确认信息</Heading>
      <Text>您输入的邮箱是:{formData.email}</Text>
    </Box>
  );
}

注意:页面刷新后Context数据会丢失,若需持久化可选用下面的方案。


方案2:Cookie存储临时数据(支持页面刷新)

将表单数据存入Cookie,跳转后读取,适合需要临时持久化数据的场景。

1. 修改NewForm组件提交逻辑

'use client';

import { useForm } from 'react-hook-form';
import { Box, FormControl, Input, Button, Text } from '@chakra-ui/react';
import { useRouter } from 'next/navigation';

type NewFormType = { email: string };

export const NewForm = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<NewFormType>();
  const router = useRouter();

  // 设置Cookie
  const setCookie = (name: string, value: string, days: number = 1) => {
    const expires = new Date();
    expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
    document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/`;
  };

  const onSubmit = handleSubmit((data) => {
    setCookie('tempEmail', data.email);
    router.push('/xxx/confirm');
  });

  return (
    <Box p={4}>
      <form onSubmit={onSubmit}>                      
        <FormControl isInvalid={!!errors.email} mb={4}>
          <Input
            id="email"
            type="email"
            placeholder="请输入邮箱"
            {...register("email", { required: "邮箱不能为空" })}
          />
          {errors.email && <Text color="red.500" mt={1}>{errors.email.message}</Text>}
        </FormControl>
        <Button type="submit" colorScheme="blue">Confirm</Button>
      </form>
    </Box>
  );
};

2. 确认页面读取Cookie

'use client';

import { Box, Heading, Text } from '@chakra-ui/react';
import { useEffect, useState } from 'react';

export default function ConfirmPage() {
  const [email, setEmail] = useState<string | null>(null);

  // 获取Cookie
  const getCookie = (name: string) => {
    const value = `; ${document.cookie}`;
    const parts = value.split(`; ${name}=`);
    if (parts.length === 2) return decodeURIComponent(parts.pop()?.split(';').shift() || '');
    return null;
  };

  useEffect(() => {
    const tempEmail = getCookie('tempEmail');
    setEmail(tempEmail);
    // 读取后清除Cookie,避免残留
    document.cookie = 'tempEmail=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;';
  }, []);

  if (!email) {
    return <Box p={4}>请先填写表单</Box>;
  }

  return (
    <Box p={4}>
      <Heading size="md" mb={4}>确认信息</Heading>
      <Text>您输入的邮箱是:{email}</Text>
    </Box>
  );
}

方案3:Server Actions + 服务器会话(App Router推荐,安全持久)

通过Next.js Server Actions提交表单,将数据存入服务器会话(如iron-session),适合需要安全存储数据的场景。

1. 安装依赖

npm install iron-session

2. 配置会话

// app/lib/session.ts
import { IronSessionOptions } from 'iron-session';

export const sessionOptions: IronSessionOptions = {
  password: process.env.SESSION_PASSWORD as string, // 需在.env中设置至少32位的密钥
  cookieName: 'form-session',
  cookieOptions: {
    secure: process.env.NODE_ENV === 'production',
  },
};

declare module 'iron-session' {
  interface IronSessionData {
    tempEmail?: string;
  }
}

3. 创建Server Action

// app/actions/formActions.ts
'use server';

import { cookies } from 'next/headers';
import { sessionOptions } from '../lib/session';

export async function submitForm(data: { email: string }) {
  const session = await cookies().getIronSession(sessionOptions);
  session.tempEmail = data.email;
  await session.save();
}

4. 修改NewForm组件调用Action

'use client';

import { useForm } from 'react-hook-form';
import { Box, FormControl, Input, Button, Text } from '@chakra-ui/react';
import { useRouter } from 'next/navigation';
import { submitForm } from '../actions/formActions';

type NewFormType = { email: string };

export const NewForm = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<NewFormType>();
  const router = useRouter();

  const onSubmit = handleSubmit(async (data) => {
    await submitForm(data);
    router.push('/xxx/confirm');
  });

  return (
    <Box p={4}>
      <form onSubmit={onSubmit}>                      
        <FormControl isInvalid={!!errors.email} mb={4}>
          <Input
            id="email"
            type="email"
            placeholder="请输入邮箱"
            {...register("email", { required: "邮箱不能为空" })}
          />
          {errors.email && <Text color="red.500" mt={1}>{errors.email.message}</Text>}
        </FormControl>
        <Button type="submit" colorScheme="blue">Confirm</Button>
      </form>
    </Box>
  );
};

5. 确认页面读取会话数据

// app/xxx/confirm/page.tsx
import { Box, Heading, Text } from '@chakra-ui/react';
import { cookies } from 'next/headers';
import { sessionOptions } from '../../lib/session';

export default async function ConfirmPage() {
  const session = await cookies().getIronSession(sessionOptions);
  const email = session.tempEmail;

  // 读取后清除会话数据
  session.tempEmail = undefined;
  await session.save();

  if (!email) {
    return <Box p={4}>请先填写表单</Box>;
  }

  return (
    <Box p={4}>
      <Heading size="md" mb={4}>确认信息</Heading>
      <Text>您输入的邮箱是:{email}</Text>
    </Box>
  );
}

补充说明

原代码中Confirm按钮不在<form>标签内,无法触发表单提交,以上方案已将按钮移入表单并设置type="submit",确保点击时自动触发验证和提交逻辑。

内容的提问来源于stack exchange,提问作者amu03

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 18:47:02