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

Next.js表单双向绑定问题:切换组件时表单数据未同步至对象

解决组件切换时表单数据同步到父对象的问题

方案1:实时同步表单数据(推荐)

直接在子组件的表单控件触发onChange时,就把数据同步回父组件的状态中。这样无论何时切换组件,父对象里的数据都是最新的,无需在切换时额外处理提交逻辑。

父组件示例代码:

import { useState } from 'react';
import ComponentOne from './ComponentOne';
import ComponentTwo from './ComponentTwo';

export default function ParentPage() {
  const [index, setIndex] = useState(0);
  const [test1, setTest1] = useState({ username: '', email: '' });
  const [test2, setTest2] = useState({ address: '', phone: '' });

  // 同步ComponentOne的表单数据
  const syncTest1 = (updatedFields) => {
    setTest1(prev => ({ ...prev, ...updatedFields }));
  };

  // 同步ComponentTwo的表单数据
  const syncTest2 = (updatedFields) => {
    setTest2(prev => ({ ...prev, ...updatedFields }));
  };

  const back = () => setIndex(prev => Math.max(0, prev - 1));
  const next = () => setIndex(prev => Math.min(1, prev + 1));

  return (
    <div>
      <div className={`${index === 0 ? 'mb-10 w-full' : 'hidden'}`}>
        <ComponentOne test={test1} onSync={syncTest1} />
      </div>

      <div className={`${index === 1 ? 'mb-10 w-full' : 'hidden'}`}>
        <ComponentTwo test={test2} onSync={syncTest2} />
      </div>
      
      <button onClick={back} className='m-5'>Previous</button>
      <button onClick={next} className='m-5'>Next</button>
    </div>
  );
}

子组件ComponentOne示例代码:

export default function ComponentOne({ test, onSync }) {
  const handleInputChange = (e) => {
    const { name, value } = e.target;
    // 把更新的字段传给父组件
    onSync({ [name]: value });
  };

  return (
    <form>
      <div>
        <label>用户名:</label>
        <input
          name="username"
          value={test.username}
          onChange={handleInputChange}
        />
      </div>
      <div>
        <label>邮箱:</label>
        <input
          name="email"
          type="email"
          value={test.email}
          onChange={handleInputChange}
        />
      </div>
    </form>
  );
}

方案2:切换组件时主动获取子组件表单数据

如果不想实时同步,可以在点击切换按钮时,主动调用子组件暴露的方法获取最新表单数据,再更新父组件的状态。

父组件示例代码:

import { useState, useRef } from 'react';
import ComponentOne from './ComponentOne';
import ComponentTwo from './ComponentTwo';

export default function ParentPage() {
  const [index, setIndex] = useState(0);
  const [test1, setTest1] = useState({ username: '', email: '' });
  const [test2, setTest2] = useState({ address: '', phone: '' });

  const compOneRef = useRef(null);
  const compTwoRef = useRef(null);

  const back = () => {
    // 切换前先保存当前组件的表单数据
    if (index === 1 && compTwoRef.current) {
      setTest2(compTwoRef.current.getFormData());
    }
    setIndex(prev => Math.max(0, prev - 1));
  };

  const next = () => {
    if (index === 0 && compOneRef.current) {
      setTest1(compOneRef.current.getFormData());
    }
    setIndex(prev => Math.min(1, prev + 1));
  };

  return (
    <div>
      <div className={`${index === 0 ? 'mb-10 w-full' : 'hidden'}`}>
        <ComponentOne ref={compOneRef} initialData={test1} />
      </div>

      <div className={`${index === 1 ? 'mb-10 w-full' : 'hidden'}`}>
        <ComponentTwo ref={compTwoRef} initialData={test2} />
      </div>
      
      <button onClick={back} className='m-5'>Previous</button>
      <button onClick={next} className='m-5'>Next</button>
    </div>
  );
}

子组件ComponentOne示例代码(使用forwardRef暴露方法):

import { forwardRef, useImperativeHandle, useState, useEffect } from 'react';

const ComponentOne = forwardRef(({ initialData }, ref) => {
  const [formData, setFormData] = useState(initialData);

  // 监听初始数据变化(比如从其他组件切回来时更新表单)
  useEffect(() => {
    setFormData(initialData);
  }, [initialData]);

  // 暴露给父组件的方法
  useImperativeHandle(ref, () => ({
    getFormData: () => ({ ...formData })
  }));

  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
  };

  return (
    <form>
      <div>
        <label>用户名:</label>
        <input
          name="username"
          value={formData.username}
          onChange={handleInputChange}
        />
      </div>
      <div>
        <label>邮箱:</label>
        <input
          name="email"
          type="email"
          value={formData.email}
          onChange={handleInputChange}
        />
      </div>
    </form>
  );
});

export default ComponentOne;

方案3:利用表单失焦事件同步

给子组件的表单添加onBlur事件,当组件失去焦点(用户点击切换按钮时)触发数据同步。不过这种方式可靠性稍差,若用户快速点击切换按钮,可能部分控件未触发失焦,建议结合前两种方案使用。

子组件表单示例:

<form onBlur={() => props.onSync(formData)}>
  {/* 表单控件 */}
</form>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 18:46:09