Skip to content

如何实现From的受控和非受控模式?

FormItem是如何获取到子组件的数据的?

这里只简单写写原理,暂时不涉及遇到的困难。

- Form用来维护一个大状态,然后通过React.Context来下放一些修改这个状态的方法:比如`getFieldValue(name)`和`setFieldValue(name, value)`等等(还有其他函数,比如校验或者报错等等)

- FormItem通过React.Context来获取到Form的状态,然后根据name来获取到对应的值。 再使用`React.cloneElement`来把获取到的Value和onChange函数传递给包裹Input组件
js
// FormItem 内部简化逻辑
function FormItem({ children, name }) {
  // 1. 从 Context 中获取表单状态和方法
  const { getFieldValue, setFieldValue } = useContext(FormContext);

  // 2. 获取当前字段的值
  const value = getFieldValue(name);

  // 3. 创建一个新的 onChange 处理器
  const handleChange = (e) => {
    const newValue = e.target.value; // 简化处理,实际情况更复杂
    setFieldValue(name, newValue);
  };

  // 4. 【核心】克隆子元素,并注入新的 props
  const controlledChild = React.cloneElement(children, {
    value: value,           // 注入从中央 state 来的 value
    onChange: handleChange,   // 注入我们自己包装过的 onChange
  });

  // 5. 渲染被“魔改”过的子元素
  return (
    <div className="form-item">
      {/* ... 可能还有 Label, 错误提示等 ... */}
      {controlledChild}
    </div>
  );
}

<Form>
  <FormItem name="username">
    <Input placeholder="请输入用户名" />
  </FormItem>
</Form>

<Input
  placeholder="请输入用户名"
  value={formState.username} // 来自 Form 的 state
  onChange={formItemCreatedChangeHandler} // FormItem 创建的 handler
/>
追问:
  1. “如果 FormItem 的 children 不是一个单一的React元素,而是一个被 div 包裹的元素,或者是一个返回 null 的组件,你的 cloneElement 会不会报错?你该如何使你的 FormItem 更健壮?”

    • “拷问”意图: 考察你对 React.Children API 的了解。 React.cloneElement 要求第一个参数必须是合法的React元素。你需要回答使用 React.Children.only 来做校验,或者遍历 children 找到需要注入的那个目标元素,这体现了你的代码鲁棒性思维。

    “所有组件都遵循 value / onChange 协议吗?比如 Ant Design 的 Switch 组件,它的值属性是 checked ,变化的回调是 onChange 但参数不是 event 。你的 FormItem 如何适配这种‘非标准’组件?”

    • “拷问”意图: 考察你的组件设计灵活性和扩展性。优秀的 FormItem 设计会提供额外的 prop,比如 valuePropName (默认为 'value') 和 trigger (默认为 'onChange'),允许使用者自定义 FormItem 从子组件的哪个 prop 上取值,以及监听哪个 prop 的变化。例如:

    “你刚才的实现中,每次 FormItem 重新渲染都会创建一个新的 handleChange 函数,这会不会有性能问题?你如何优化?”

    • “拷问”意图: 考察你对React性能优化的理解。你需要回答可以使用 useCallback 来缓存这个 handleChange 函数,避免在子组件的 props 上产生不必要的变更,从而减少子组件的重渲染。
本站访客数 人次 本站总访问量