受控组件与非受控组件选择方案 - 图1

非受控组件

就如传统的 HTML 表单

  1. class Form extends Component {
  2. render() {
  3. return (
  4. <div>
  5. <input type="text" />
  6. </div>
  7. );
  8. }
  9. }

使用一个 ref 来得到表单控件的值

  1. class Form extends Component {
  2. handleSubmitClick = () => {
  3. const name = this._name.value;
  4. // do something with `name`
  5. }
  6. render() {
  7. return (
  8. <div>
  9. <input type="text" ref={input => this._name = input} />
  10. <button onClick={this.handleSubmitClick}>Sign up</button>
  11. </div>
  12. );
  13. }
  14. }

换言之,当你需要时,可以从 input 中拉取值 ( pull )。这是一个最简单的方法去实现 form input 的取值。这是一个明确有效的方案。 在实际开发中,对于简单的表单可以使用非受控组件来操作。

受控组件

受控组件接收一个当前值的 prop,并且也要有一个回调来改变这个值。
这是一个更接近于 React 的方式 来处理表单的方式,但不意味应该就总是这样使用受控组件。

  1. <input value={someValue} onChange={handleChange} />

受控组件中的值必需常驻于 state 里。跟 input 相关的渲染表单组件要保存在 state。
当然也可以保存至其它的组件的 state,即通过 props,传递另外组件的 state。又或者 Redux 也通过 props 传递过来。

每次输入新的字符时,handleNameChange 都会调用。以一个新的值设置至 state
受控组件与非受控组件选择方案 - 图2

  • 开始 state.name 是空字符串
  • 输入一个 a 来使 handleNameChange 得到一个 a,然后调用 setState。然后这个组件重新渲染得到值 a
  • 再输入一个 bhandleNameChange 得到一个 ab 的值,然后设置 state。组件再次渲染,现在 value="ab"

类似这种把值推进( push )表单组件的流,表单组件总会有当前 Input 的值而不需要明确地询问其值 。意味 state 与 input 的值是同步绑在一起了。
也意味会 state 会立即反映表单的改变,如

  • 适当的反馈,如验证
  • 按键会根据所有表单的合法性来开启 disabled
  • 强制输入一些明确格式,如信用卡号

如果不这上面这些情况,可以考虑使用非受控组件。

一人上表单元素成为受控组件,要通过一个 prop。不同表单元素可能要通过不同的 prop 来设置其值:

元素 属性值 回调函数 回调通过什么取得新值
value=”string” onChange event.target.value
checked={boolean} onChange event.target.checked
checked={boolean} onChange event.target.checked
value=”string” onChange event.target.value
value=”option value” onChange event.target.value

结论

受控与非受控表单都 有各自的优点。评估现在的情况而选择最佳的方案:
如果 UI 反馈是简单的,非受控组件用 refs 是没有问题的。不需要听那些文章说非受控组件是不行的。

特征 非受控组件 受控组件
只有一次获取值的 (如: submit)
提交需要验证
即时的表单验证
根据情况来 disable 按键的
当输入时强制格式化的
有几个 input 且是一组数据的
动态 input