受控组件(受state控制)
在 HTML 中,表单元素如 <input>,<textarea> 和 <select> 表单元素通常保持自己的状态,并根据用户输入进行更新。而在 React 中,可变状态一般保存在组件的 state(状态) 属性中,并且只能通过 setState() 更新。
我们可以通过使 React 的 state 成为 “单一数据源原则” 来结合这两个形式。然后渲染表单的 React 组件也可以控制在用户输入之后的行为。这种形式,其值由 React 控制的输入表单元素称为“受控组件”。
非受控组件(不受state控制,可通过ref属性控制)
其表单数据由 DOM 元素本身处理。要编写一个未控制组件,我们可以使用一个 ref 来从 DOM 获得 表单值,而不是为每个状态更新编写一个事件处理程序。
因为不受控组件的数据来源是 DOM 元素,当使用不受控组件时很容易实现 React 代码与非 React 代码的集成。如果你希望的是快速开发、不要求代码质量,不受控组件可以一定程度上减少代码量。否则。我们应该使用受控组件。
摘录自 react 官方文档
在React 16版本下,非受控组件也发生了一定的变化。
首先加入的React.StrictMode(严格模式)可以对程序中的任何部分都启用严格模式。
其次StrictMode和Fragment一样,都不会渲染任何可见的UI.
最后StrictMode有助于:
- 识别不安全的生命周期
- 关于使用过时字符串 ref API 的警告
- 关于使用废弃的 findDOMNode 方法的警告
- 检测意外的副作用
- 检测过时的 context API
下面重点说下 ref
我们之前常用到 ref的方式有两种。一种是 ref=””(已废弃),另一种是ref={ref=>this.xx=ref}
接下来看两个例子:
// 第一种 ref的值为字符串时export default class Main extends React.Component {handleChange = () => {console.log("this.refs:", this.refs);let a = parseInt(this.refs.a.value || 0);let b = parseInt(this.refs.b.value || 0);this.refs.result.value = a + b;}render() {return (<div onChange={this.handleChange}><input ref="a" type="text" /> +<input ref="b" type="text" /> =<input ref="result" type="text" /></div>);}}使用严格模式时会有如下警告:

在React中,组件的实例化工作是由React自动完成的,组件实例也是直接由React管理的。换句话说,开发者完全不必关心组件实例的创建、更新和销毁。
// 第二种 ref的值为回调函数时export default class Main extends React.Component {handleChange = () => {console.log("this.refs:", this.refs);let a = parseInt(this.a.value || 0);let b = parseInt(this.b.value || 0);this.result.value = a + b;}render() {return (<div onChange={this.handleChange}><input ref={ref=>this.a=ref} type="text" /> +<input ref={ref=>this.b=ref} type="text" /> =<input ref={ref=>this.result=ref} type="text" /></div>);}}使用严格模式不会有警告:

// React 16.3 新增了第三种选择,它提供了使用字符串 ref 的便利性,并且不存在任何缺点export default class Main extends React.Component {constructor(props) {super(props);this.state ={};this.inputA = React.createRef();this.inputB = React.createRef();this.inputResult = React.createRef();}handleChange = () => {console.log("this.refs:", this.refs);let a = parseInt(this.inputA.current.value || 0);let b = parseInt(this.inputB.current.value || 0);this.inputResult.current.value = a + b;}render() {return (<div onChange={this.handleChange}><input ref={this.inputA} type="text" /> +<input ref={this.inputB} type="text" /> =<input ref={this.inputResult} type="text" /></div>);}componentDidMount() {this.inputA.current.focus();this.inputB.current.focus();}}

注意:
除了新增加的 createRef API,回调 ref 依旧适用。
你无需替换组件中的回调 ref。它们更灵活,因此仍将作为高级功能保留。
