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

Next.js注册表单处理邀请Token遇加载问题及Hook报错求助

问题分析与解决方案

核心问题原因

  1. 钩子调用违规:useSWR被放在条件判断块中,违反React钩子必须在组件顶层调用的规则,导致Rendered more hooks than during the previous render错误。
  2. 加载状态混乱:多个加载状态(isLoading、loading、SWR请求状态)未统一处理,请求Token有效性期间没有正确显示加载器。
  3. 渲染逻辑顺序错误:Token验证请求完成前,组件直接渲染了标准表单,导致页面先显示标准表单再更新。

修正后的完整代码

import { useState, useEffect } from 'react'
import { useRouter } from 'next/router'
import useSWR from 'swr'
import axios from 'axios'
import PageLoader from './PageLoader' // 根据实际路径调整

const Register = () => {
  const router = useRouter()
  const { register, isLoading: authLoading } = useAuth({
    middleware: 'guest',
    redirectIfAuthenticated: '/dashboard',
  })

  const [inviteToken, setInviteToken] = useState('')
  const [formLoading, setFormLoading] = useState(false)
  const [errors, setErrors] = useState([])
  const [inviteEmail, setInviteEmail] = useState('')
  // 需补充表单自身的状态定义
  const [firstName, setFirstName] = useState('')
  const [lastName, setLastName] = useState('')
  const [email, setEmail] = useState('')

  // 监听URL中的token变化,更新inviteToken
  useEffect(() => {
    if (router.query.token?.length > 0) {
      setInviteToken(router.query.token)
      setErrors([])
      setInviteEmail('')
    } else {
      setInviteToken('')
      setInviteEmail('')
    }
  }, [router.query.token])

  // 顶层调用useSWR,仅当存在inviteToken时发起请求
  const { 
    data: inviteData, 
    error: inviteError, 
    isLoading: isInviteLoading 
  } = useSWR(
    inviteToken ? `/api/retrieve-invite/${inviteToken}` : null,
    (url) => axios.get(url).then(res => res.data.data)
  )

  // 处理Token验证结果
  useEffect(() => {
    if (inviteError) {
      setErrors(['Token无效'])
      setInviteEmail('')
    } else if (inviteData) {
      setInviteEmail(inviteData.email) // 假设接口返回数据包含email字段
      setErrors([])
    }
  }, [inviteData, inviteError])

  // 表单提交逻辑
  const submitForm = async (event) => {
    event.preventDefault()
    setFormLoading(true)

    try {
      await register({
        first_name: firstName,
        last_name: lastName,
        email: inviteEmail || email
      })
    } catch (err) {
      setErrors(err.response?.data?.errors || ['注册失败'])
    } finally {
      setFormLoading(false)
    }
  }

  // 统一处理所有加载状态
  if (authLoading || isInviteLoading || formLoading) {
    return <PageLoader />
  }

  return (
    <div className="register-container">
      {/* 错误提示 */}
      {errors.length > 0 && (
        <div className="error-message">
          {errors.map((err, idx) => <p key={idx}>{err}</p>)}
        </div>
      )}

      {/* 注册表单 */}
      <form onSubmit={submitForm}>
        {/* 邮箱输入:邀请注册时预填并禁用 */}
        <div>
          <label>邮箱</label>
          <input
            type="email"
            value={inviteEmail || email}
            onChange={(e) => !inviteEmail && setEmail(e.target.value)}
            disabled={!!inviteEmail}
            required
          />
        </div>

        <div>
          <label>名字</label>
          <input
            type="text"
            value={firstName}
            onChange={(e) => setFirstName(e.target.value)}
            required
          />
        </div>

        <div>
          <label>姓氏</label>
          <input
            type="text"
            value={lastName}
            onChange={(e) => setLastName(e.target.value)}
            required
          />
        </div>

        <button type="submit" disabled={formLoading}>
          {formLoading ? '注册中...' : '注册'}
        </button>
      </form>
    </div>
  )
}

export default Register

关键修正点说明

  • 钩子规则修复:将useSWR移至组件顶层,通过传递null作为请求URL,实现仅当存在Token时发起请求的逻辑,避免条件性调用钩子。
  • 统一加载状态:整合authLoading(登录状态验证)、isInviteLoading(Token验证请求)、formLoading(表单提交)三个状态,任一状态为true时显示加载器。
  • Token逻辑优化:通过useEffect监听URL中token的变化,自动更新验证状态;验证完成后根据结果设置预填邮箱或错误提示,确保请求过程中不会提前渲染表单。
  • 表单逻辑调整:邀请注册时自动预填邮箱并禁用输入,提交时优先使用预填邮箱,保证邀请场景的正确性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 04:28:10