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

React useState管理表单数据在iPhone上无法传递至PHP的问题

解决React表单在iPhone上提交时文本字段$_POST丢失的问题

问题分析

核心问题:React受控表单在iPhone Safari中提交时,仅数字类型的state字段(成人/儿童数)能正常传递到WordPress的PHP页面,文本类型字段(姓名、邮箱、酒店名等)的$_POST数据丢失,但硬编码所有值时所有设备均正常。

结合给出的特殊情况,问题根源大概率是:

  1. React state更新的异步特性与Safari表单默认提交的同步机制冲突,提交时文本字段的state尚未完成更新,表单提交的仍是初始空值;
  2. Safari对application/x-www-form-urlencoded编码的受控组件值处理存在差异,自动序列化时未正确捕获文本字段的最新值。

解决方案

方案1:阻止表单默认提交,手动构造请求发送数据

通过手动处理提交逻辑,确保使用最新的state值构造请求数据,避免浏览器自动序列化的差异。

先修复代码语法错误

将handleHotelChange从handleSubmit内部移到组件顶层,避免函数未定义问题:

import { useState } from 'react';

const BookingForm = () => {
  const [firstName, setFirstName] = useState('');
  const [surName, setSurName] = useState('');
  const [email, setEmail] = useState('');
  const [phone, setPhone] = useState('');
  const [date, setDate] = useState('');
  const [adultCount, setAdultCount] = useState(0);
  const [childCount, setChildCount] = useState(0);
  const [infantCount, setInfantCount] = useState(0);
  const [hotelName, setHotelName] = useState('');
  const [message, setMessage] = useState('');
  const [errorHotel, setErrorHotel] = useState('');

  // 移到组件顶层
  const handleHotelChange = (e) => {
    const value = e.target.value;
    setHotelName(value);
    if (value.trim() === '' && packages.tourTypeId !== 3) {
      setErrorHotel('Hotel name required!');
    } else {
      setErrorHotel('');
    }
  };

  const handleSubmit = async (e) => {
    e.preventDefault(); // 阻止表单默认提交行为

    // 用FormData构造数据(PHP可直接通过$_POST获取)
    const formData = new FormData();
    formData.append('first_name', firstName);
    formData.append('sur_name', surName);
    formData.append('email', email);
    formData.append('phone', phone);
    formData.append('date', date);
    formData.append('adult_count', adultCount);
    formData.append('child_count', childCount);
    formData.append('infant_count', infantCount);
    formData.append('hotel_name', hotelName);
    formData.append('message', message);

    try {
      const response = await fetch(site_url('/request-summary'), {
        method: 'POST',
        body: formData
      });

      // 提交成功后跳转或处理响应
      if (response.ok) {
        window.location.href = site_url('/request-summary');
      }
    } catch (error) {
      console.error('提交失败:', error);
    }
  };

  return (
    <form
      ref={tourDataFormRef}
      onSubmit={handleSubmit}
      name='frm'
      id='bookingform'
    >
      <input
        id="hotel-name"
        name="hotel_name"
        type="text"
        value={hotelName}
        onChange={handleHotelChange}
        className="w-full px-1 py-1 border rounded-md cursor-pointer border-body border-opacity-30 placeholder:text-neutral-200 sm:text-sm sm:leading-6"
      />
      {/* 其他表单字段按原有逻辑保留 */}
      <button type="submit">Submit</button>
    </form>
  );
};

方案2:用useRef实时同步字段值,规避异步更新延迟

如果坚持使用表单默认提交,可通过useRef实时存储字段值,避免React异步更新的延迟影响:

import { useState, useRef } from 'react';

const BookingForm = () => {
  const [firstName, setFirstName] = useState('');
  const [surName, setSurName] = useState('');
  const [hotelName, setHotelName] = useState('');
  const [errorHotel, setErrorHotel] = useState('');
  // 用ref实时存储字段值
  const firstNameRef = useRef('');
  const surNameRef = useRef('');
  const hotelNameRef = useRef('');

  const handleHotelChange = (e) => {
    const value = e.target.value;
    hotelNameRef.current = value; // 同步更新ref
    setHotelName(value);
    if (value.trim() === '' && packages.tourTypeId !== 3) {
      setErrorHotel('Hotel name required!');
    } else {
      setErrorHotel('');
    }
  };

  const handleSubmit = () => {
    // 用ref的值同步state,确保一致性
    setFirstName(firstNameRef.current);
    setSurName(surNameRef.current);
    setHotelName(hotelNameRef.current);
  };

  return (
    <form
      ref={tourDataFormRef}
      onSubmit={handleSubmit}
      encType="application/x-www-form-urlencoded"
      method='post'
      name='frm'
      id='bookingform'
      action={site_url('/request-summary')}
    >
      <input
        id="first-name"
        name="first_name"
        type="text"
        ref={firstNameRef}
        onChange={(e) => firstNameRef.current = e.target.value}
        value={firstName}
        className="..."
      />
      {/* 其他文本字段同理,用ref同步值 */}
      <input
        id="hotel-name"
        name="hotel_name"
        type="text"
        ref={hotelNameRef}
        onChange={handleHotelChange}
        value={hotelName}
        className="..."
      />
      
      <button type="submit">Submit</button>
    </form>
  );
};

关键说明

  • 方案1是更可靠的选择,完全规避浏览器对表单序列化的差异,同时能灵活处理提交状态(如加载提示、错误处理);
  • 数字字段能正常传递是因为初始值为0,即使state未更新,表单提交的初始值也能被PHP捕获,而文本字段初始值为空字符串,所以$_POST中无对应数据;
  • 硬编码值能正常工作是因为直接使用固定值,不受React异步更新的影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:24:51