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

复用动态Select组件onChange触发多事件,是否需拆分组件?

问题解答

核心结论

不需要为每个select单独创建组件,你的问题和this完全无关(函数组件里this本身就是undefined,你控制台打印的this也能证明这点),真正的问题是每个FlightTypeComponent实例都独立初始化了useForm钩子,导致表单状态和逻辑重复,所以两个组件触发事件都会输出内容。

问题分析

  1. 函数组件里的this:你写的是函数组件,这类组件没有类组件的this上下文,所以console.log(this)打印出来必然是undefined,完全不用怀疑是this导致两个组件关联的问题。
  2. useForm重复初始化的影响:每个FlightTypeComponent都调用了useForm,意味着每个组件都有自己独立的表单状态、register/unregister/setValue等方法。这就导致两个组件的表单逻辑完全独立,各自触发onChange时,都会执行自己的regionSetter和console.log(watch()),所以控制台会多次输出内容。

解决方案

把useForm提升到父组件中,将表单相关的方法通过props传递给FlightTypeComponent,让所有组件共享同一个表单状态:

父组件示例

import { useForm } from "react-hook-form";

const ParentComponent = () => {
  // 只在父组件初始化一次useForm
  const { register, unregister, watch, setValue, formState: {errors} } = useForm({
    defaultValues: {
      flights: {
        domestic: "",
        international: ""
      }
    }
  });

  const {flightType, flightTypeClick} = useBookingContext();

  console.log(watch());

  return (
    <div>
      {/* 传递表单方法给子组件 */}
      <FlightTypeComponent 
        flights={yourFlightsData} 
        flightLocalType="domestic"
        unregister={unregister}
        setValue={setValue}
        flightType={flightType}
        flightTypeClick={flightTypeClick}
      />
      <FlightTypeComponent 
        flights={yourFlightsData} 
        flightLocalType="international"
        unregister={unregister}
        setValue={setValue}
        flightType={flightType}
        flightTypeClick={flightTypeClick}
      />
    </div>
  );
};

修改后的FlightTypeComponent

// 接收父组件传递的表单方法
const FlightTypeComponent = ({flights, flightLocalType, unregister, setValue, flightType, flightTypeClick}) => {
  const regionSetter = (regionType, regionValue) => {
    if (regionType === "international") {
      unregister("flights.domestic");
    }
    if (regionType === "domestic") {
      unregister("flights.international");
    }
    setValue(`flights.${regionType}`, regionValue);
    flightTypeClick(regionType, regionValue);
  };

  return (
    <div className="flex flex-col">
      <label className='absolute z-10'>{flightLocalType}</label>
      <select 
        className={`${flightType === flightLocalType ? `bg-amber-200` : `bg-white`} relative h-20`} 
        onChange={(e) => regionSetter(flightLocalType, e.currentTarget.value)}
      >
        <option value="">___</option>
        {flights.map(({region, location}) => (
          {/* 给optgroup加上key,避免React警告 */}
          <optgroup key={region} label={region}>
            {Object.keys(location).map((eachProvince, index) => (
              <option key={index} value={eachProvince}>{eachProvince}</option>
            ))}
          </optgroup>
        ))}
      </select>
    </div>
  );
};

额外优化点

  • 删掉regionSetter里的console.log(this),函数组件里它没有任何实际作用;
  • 清理了原select className里多余的单引号(原代码中'relative h-20 '的单引号是冗余的);
  • 给optgroup添加了key属性,解决React列表渲染的警告问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 03:55:32