React Hooks 中的「受控组件」和 「非受控组件」

522 阅读3分钟

受控组件

  • input 可以设置 valuechecked 属性
  • 可以监听 onChange 事件,更新 state
const NoteSection: React.FC = () => {
  const [note, setNote] = useState('')
  return (
    <label>
      <span>备注</span>
      <input type="text" placeholder="在这里添加备注"
        value={ note }
        onChange={ (e)=> setNode(e.target.value) } 
      />
    </label>
  )
}

以上更新 state 的流程:

  • 可以通过初始 state 中设置表单的默认值
  • 每当表单的值发生变化时,调用 onChange 事件处理器
  • 事件处理器通过事件对象 e 拿到改变后的状态,并更新组件的 state
  • 一旦通过 setState 方法更新state,就会触发视图的重新渲染,完成表单组件的更新

缺陷:

表单元素的值都是由 React 组件进行管理,当有多个输入框,或者多个这种组件时,如果想同时获取到全部的值就必须每个都要编写事件处理函数,这会让代码看着很臃肿,所以为了解决这种情况,出现了非受控组件。

非受控组件

非受控模式:

  • 你中间的过程我不想控制,结束的时候我通过 ref 从 DOM 获得表单最新值。
  • 不用为每个状态更新编写一个事件处理程序。
  • 一个表单组件没有 value props(单选和复选按钮对应的是 checked props )
const NoteSection: React.FC = () => {
  const [note, setNote] = useState('')
  // 当用户的鼠标移出 input 的时候,就调用 x
  const x = () => {
    // 这个 x 怎么获取到最新的 note 值呢?
    // 直接读 note 是不行的,因为现在 input 根本就没有把 note 的最新值传给 note
    // 只能去获取 input 的 value!
  }
  return (
    <label>
      <span>备注</span>
      <input type="text" placeholder="在这里添加备注"
        defaultValue={note}
        onBlur={x}
      />
    </label>
  )
}
const NoteSection: React.FC = () => {
  // useState 钩子把初始状态作为一个参数,所以 note 状态变量将被初始化为默认值
  const [note, setNote] = useState('')
  const refInput = useRef<HTMLInputElement>(null)
  const onBlur = () => {
    if (refInput.current !== null) {
      setNote(refInput.current.value)  
    }
  }
  return (
    <label>
      <span>备注</span>
      { /* 
        当使用非受控组件时,提前创建好 ref 对象 refInput,
        将创建出来的对象绑定到 input 元素, 我们使用 ref 来访问输入,从 DOM 节点中获取表单数据
        如果你用 ref = { refInput } 向 React 传递一个可变的 ref 对象,这个对象就是 refInput
        React就会将其 .current 属性 设置为相应的 DOM 节点,只要该节点发生变化
        要为一个不受控制的输入字段设置一个默认值,请在该字段上设置 defaultValue
        你可以用 defaultValue 给一个不受控制的输入 传递一个初始值
        把 note 作为初始值传给 defaultValue 作为默认值
      */ }
      <input 
        type="text" 
        placeholder="在这里添加备注"
        ref={ refInput }
        defaultValue={ note }
        onBlur={ onBlur }
      />
    </label>
  )
}

总结

  • 同时设置 valuedefaultValue 是不允许的
  • 非受控组件上 defaultValue 不是必须的,可以省略
  • 在一个非受控组件(一个没有 onChange 处理程序的输入字段)上设置 value,这将使输入字段变得不可改变,你将无法在其中打字。
  • 非受控模式使用场景:你中间的过程我不想控制,结束的时候我通过 ref 去读取最新的值。
  • 页面中所有输入类的 DOM 如果是现用现取的称为非受控组件,而通过 setState 将输入的值维护到了 state 中,需要时再从 state 中取出,这里的数据就受到了 state 的控制,称为受控组件。