网上多数文章仅仅讲述了受控组件和非受控组件的概念,并没有讲述为什么会存在这两种类型组件以及它们的应用场景。本文将对这些遗留问题进行介绍。

1、什么是受控组件和非受控组件?

受控组件
在 HTML 中,表单元素(如<input><textarea><select>)之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用setState()来更新。

我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

由于在表单元素上设置了value属性,因此显示的值将始终为this.state.value,这使得 React 的 state 成为唯一数据源。由于handlechange在每次按键时都会执行并更新 React 的 state,因此显示的值将随着用户输入而更新。

对于受控组件来说,每个 state 突变都有一个相关的处理函数。这使得修改或验证用户输入变得简单。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>受控组件</title>
  <script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
  <!-- <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> -->
  <!-- <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script> 
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
    class NameForm extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          name: '',
          pwd: ''
        }
        this.handleChange = this.handleChange.bind(this)
        this.handleSubmit = this.handleSubmit.bind(this)
      }

      handleChange(e) {
        console.log(e)
        var key = e.target.name
        var value = e.target.value
        this.setState({[key]: value})
      }

      handleSubmit(e) {
        alert('姓名:' + this.state.name +  ' 密码:' + this.state.pwd)
        e.preventDefault()
      }

      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              名字:
              <input type="text" name="name" value={this.state.name} onChange={this.handleChange} />
              <br/>
              密码:
              <input type="password" name="pwd" value={this.state.pwd} onChange={this.handleChange} />
            </label>
            <br/>
            <input type="submit" value="提交" />
          </form>
        )
      }
    }
    ReactDOM.render(
      <NameForm />,
      document.getElementById('root')
    )
  </script>
</body>
</html>

非受控组件
要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref 来从 DOM 节点中获取表单数据。

因为非受控组件将真实数据储存在 DOM 节点中,所以再使用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码美观性,并且希望快速编写代码,使用非受控组件往往可以减少你的代码量。否则,你应该使用受控组件。

在 React 渲染生命周期时,表单元素上的 value 将会覆盖 DOM 节点中的值,在非受控组件中,你经常希望 React 能赋予组件一个初始值,但是不去控制后续的更新。 在这种情况下, 你可以指定一个 defaultValue 属性,而不是 value。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>非受控组件</title>
  <script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
  <!-- <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> -->
  <!-- <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script> 
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
    class NameForm extends React.Component {
      constructor(props) {
        super(props)
        this.handleSubmit = this.handleSubmit.bind(this)
      }
      handleSubmit(e) {
        e.preventDefault()
        console.log(this.input)
        alert(this.input.value)
      }
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              名字:
              <input name="username" type="text" defaultValue="123456" ref={username => this.input = username} />  
            </label> 
            <input type="submit" value="提交" />
          </form>
        )
      }
    }
    ReactDOM.render(
      <NameForm />,
      document.getElementById('root')
    )
  </script>
</body>
</html>

我们可以简单总结一下两种类型组件的区别:
1、受控组件表单数据由state管理,非受控组件表单数据由DOM节点管理;
2、受控组件表单数据变更具有实时性,具有双向数据绑定特性,非受控组件表单数据是一次性的,需要时读取,受控组件能帮助我们更好的控制表单元素。

2、两者适应场景

根据上述的比较,我们可以总结出它们的应用场景
1.png

参考:
https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/


记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。