非受控组件
就如传统的 HTML 表单
class Form extends Component {render() {return (<div><input type="text" /></div>);}}
使用一个 ref 来得到表单控件的值
class Form extends Component {handleSubmitClick = () => {const name = this._name.value;// do something with `name`}render() {return (<div><input type="text" ref={input => this._name = input} /><button onClick={this.handleSubmitClick}>Sign up</button></div>);}}
换言之,当你需要时,可以从 input 中拉取值 ( pull )。这是一个最简单的方法去实现 form input 的取值。这是一个明确有效的方案。 在实际开发中,对于简单的表单可以使用非受控组件来操作。
受控组件
受控组件接收一个当前值的 prop,并且也要有一个回调来改变这个值。
这是一个更接近于 React 的方式 来处理表单的方式,但不意味应该就总是这样使用受控组件。
<input value={someValue} onChange={handleChange} />
受控组件中的值必需常驻于 state 里。跟 input 相关的渲染表单组件要保存在 state。
当然也可以保存至其它的组件的 state,即通过 props,传递另外组件的 state。又或者 Redux 也通过 props 传递过来。
每次输入新的字符时,handleNameChange 都会调用。以一个新的值设置至 state
- 开始 state.name 是空字符串
- 输入一个
a来使handleNameChange得到一个a,然后调用setState。然后这个组件重新渲染得到值a - 再输入一个
b。handleNameChange得到一个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 | ❌ | ✅ |
