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

Next.js/React表单代码执行顺序异常问题求助

解决方案

问题核心在于:表单的onClick是同步触发的,而useFormState绑定的formAction(即userLogin)是异步执行的,所以必然是onClick先跑,没法直接调整两者的执行顺序。正确的做法是利用useFormState的状态变化来感知登录动作的完成,再执行后续清理逻辑,具体如下:

方法一:通过useEffect监听登录状态变化

移除按钮上的onClick,改用useEffect监听formState的更新——当formState从初始值(status: -1)变化时,说明userLogin已执行完成,此时再做清理或状态更新:

"use client";
import { useState, ChangeEvent, useEffect } from 'react';
import { useFormState } from "react-dom";

import { userLogin } from "...";

export interface LoginResponse {
  status: number;
}

const initialState: LoginResponse = {
  status: -1,
};

const Login = () => {
  const [formState, formAction] = useFormState(userLogin, initialState);
  const [inpMail, setInpMail] = useState('')
  const [logMail, setLogMail] = useState('')

  function mailUpdate(evt: ChangeEvent<HTMLInputElement>) {
    setInpMail(evt.target.value)
  }

  // 监听登录状态变化,完成后执行后续操作
  useEffect(() => {
    // 初始状态为-1,状态变化说明登录动作已完成
    if (formState.status !== -1) {
      setLogMail(inpMail);
      setInpMail(''); // 执行清理工作
      
      // 可选:如果需要重置登录状态,避免重复触发
      // 可以在userLogin中返回初始状态,或者用ref标记是否已处理
    }
  }, [formState, inpMail]);

  return(
    <div className="flex flex-col min-h-fit bg-slate-300 w-1/2 items-center" >
      {/* ...其他页面内容... */}
      <form className="p-4 flex flex-col w-80 bg-stone-300 items-center"
            action={formAction} method="post" >
        <input type="email" value={inpMail} onChange={mailUpdate} name="email" />
        {/* ...其他输入框... */}
        <button className="bg-cyan-500 text-xl rounded-lg w-1/3"
                type="submit">Login</button>
      </form>
    </div>
  )
}

export default Login;

方法二:在userLogin中返回提交数据,保证数据一致性

如果担心组件状态inpMail和表单实际提交的数据不一致,可以修改userLogin从FormData中获取邮箱,并将其包含在返回的状态中,再在useEffect中使用该数据:

  1. 更新响应接口:
export interface LoginResponse {
  status: number;
  email?: string;
}
  1. 修改userLogin函数:
async function userLogin(prevState: LoginResponse, formData: FormData) {
  const email = formData.get('email') as string;
  // 执行登录逻辑
  const res = await fetch('/api/login', {
    method: 'POST',
    body: formData,
  });
  const data = await res.json();
  
  return {
    status: res.status,
    email: email,
  };
}
  1. 调整useEffect逻辑:
useEffect(() => {
  if (formState.status !== -1 && formState.email) {
    setLogMail(formState.email);
    setInpMail('');
  }
}, [formState]);

这样能确保使用的是表单实际提交的邮箱数据,避免组件状态和提交数据不同步的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:07:14