受控组件(受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有助于:

  1. // 第一种 ref的值为字符串时
  2. export default class Main extends React.Component {
  3. handleChange = () => {
  4. console.log("this.refs:", this.refs);
  5. let a = parseInt(this.refs.a.value || 0);
  6. let b = parseInt(this.refs.b.value || 0);
  7. this.refs.result.value = a + b;
  8. }
  9. render() {
  10. return (
  11. <div onChange={this.handleChange}>
  12. <input ref="a" type="text" /> +
  13. <input ref="b" type="text" /> =
  14. <input ref="result" type="text" />
  15. </div>
  16. );
  17. }
  18. }
  19. 使用严格模式时会有如下警告:

截屏2020-04-03下午7.51.40.png
在React中,组件的实例化工作是由React自动完成的,组件实例也是直接由React管理的。换句话说,开发者完全不必关心组件实例的创建、更新和销毁。

  1. // 第二种 ref的值为回调函数时
  2. export default class Main extends React.Component {
  3. handleChange = () => {
  4. console.log("this.refs:", this.refs);
  5. let a = parseInt(this.a.value || 0);
  6. let b = parseInt(this.b.value || 0);
  7. this.result.value = a + b;
  8. }
  9. render() {
  10. return (
  11. <div onChange={this.handleChange}>
  12. <input ref={ref=>this.a=ref} type="text" /> +
  13. <input ref={ref=>this.b=ref} type="text" /> =
  14. <input ref={ref=>this.result=ref} type="text" />
  15. </div>
  16. );
  17. }
  18. }
  19. 使用严格模式不会有警告:

截屏2020-04-03下午7.54.05.png

  1. // React 16.3 新增了第三种选择,它提供了使用字符串 ref 的便利性,并且不存在任何缺点
  2. export default class Main extends React.Component {
  3. constructor(props) {
  4. super(props);
  5. this.state ={};
  6. this.inputA = React.createRef();
  7. this.inputB = React.createRef();
  8. this.inputResult = React.createRef();
  9. }
  10. handleChange = () => {
  11. console.log("this.refs:", this.refs);
  12. let a = parseInt(this.inputA.current.value || 0);
  13. let b = parseInt(this.inputB.current.value || 0);
  14. this.inputResult.current.value = a + b;
  15. }
  16. render() {
  17. return (
  18. <div onChange={this.handleChange}>
  19. <input ref={this.inputA} type="text" /> +
  20. <input ref={this.inputB} type="text" /> =
  21. <input ref={this.inputResult} type="text" />
  22. </div>
  23. );
  24. }
  25. componentDidMount() {
  26. this.inputA.current.focus();
  27. this.inputB.current.focus();
  28. }
  29. }

截屏2020-04-03下午8.45.57.png

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