在React中处理表单的方法

129 阅读3分钟

表格是少数几个默认为交互式的HTML元素之一。

它们被设计为允许用户与页面互动。

表格的常见用途?

  • 搜索
  • 联系表格
  • 购物车结账
  • 登录和注册
  • 以及更多!

使用React,我们可以使我们的表单更具互动性,而不是静态的。

在React中,有两种处理表单的主要方式,它们在一个基本层面上是不同的:如何管理数据。

  • 如果数据是由DOM处理的,我们称之为不受控制的组件
  • 如果数据是由组件处理的,我们称之为受控组件

正如你可以想象的那样,受控组件是你在大多数时候都会用到的。组件的状态是唯一的真理来源,而不是DOM。但有时你会被迫使用非控制组件,例如在使用一些表单字段时,这些字段由于其行为本身是不受控制的,如<input type="file"> 字段。

当由组件管理的表单字段中的元素状态发生变化时,我们使用onChange 属性来跟踪它。

class Form extends React.Component {
  constructor(props) {
    super(props)
    this.state = { username: '' }
  }

  handleChange(event) {}

  render() {
    return (
      <form>
        Username:
        <input
          type="text"
          value={this.state.username}
          onChange={this.handleChange}
        />
      </form>
    )
  }
}

对于类组件,为了设置新的状态,我们必须将this 绑定到handleChange 方法上,否则this 就无法从该方法中访问。

class Form extends React.Component {
  constructor(props) {
    super(props)
    this.state = { username: '' }
    this.handleChange = this.handleChange.bind(this)
  }

  handleChange(event) {
    this.setState({ username: event.target.value })
  }

  render() {
    return (
      <form>
        <input
          type="text"
          value={this.state.username}
          onChange={this.handleChange}
        />
      </form>
    )
  }
}

同样,当表单被提交时,我们使用表单上的onSubmit 属性来调用handleSubmit 方法。

class Form extends React.Component {
  constructor(props) {
    super(props)
    this.state = { username: '' }
    this.handleChange = this.handleChange.bind(this)
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  handleChange(event) {
    this.setState({ username: event.target.value })
  }

  handleSubmit(event) {
    alert(this.state.username)
    event.preventDefault()
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type="text"
          value={this.state.username}
          onChange={this.handleChange}
        />
        <input type="submit" value="Submit" />
      </form>
    )
  }
}

使用钩子,这一切就变得简单多了。

const Form = props => {
  const [username, setUsername] = useState()

  const handleChangeUsername = e => {
    setUsername(e.target.value)
  }

  const handleSubmit = event => {
    alert(username)
    event.preventDefault()
  }

  render() {
    return (
      <form onSubmit={handleSubmit}>
        Username:
        <input
          type="text"
          value={username}
          onChange={handleChangeUsername}
        />
      </form>
    )
  }
}

表单中的验证可以在handleChange 方法中处理:你可以访问状态的旧值和新值。你可以检查新的值,如果无效就拒绝更新的值(并以某种方式传达给用户)。

HTML表单是不一致的。它们有很长的历史,这一点很明显。然而,React使我们的事情更加一致,你可以使用它的value 属性获得(和更新)字段。

这里有一个textarea ,比如说。

<textarea value={this.state.address} onChange={this.handleChange} />

select 标签也是如此。

<select value="{this.state.age}" onChange="{this.handleChange}">
  <option value="teen">Less than 18</option>
  <option value="adult">18+</option>
</select>

之前我们提到了<input type="file"> 字段。这工作方式有点不同。

在这种情况下,你需要通过将ref 属性分配给构造函数中定义的属性(React.createRef() )来获得对该字段的引用,并使用该属性在提交处理程序中获得它的值。

class FileInput extends React.Component {
  constructor(props) {
    super(props)
    this.curriculum = React.createRef()
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  handleSubmit(event) {
    alert(this.curriculum.current.files[0].name)
    event.preventDefault()
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input type="file" ref={this.curriculum} />
        <input type="submit" value="Submit" />
      </form>
    )
  }
}

这是不受控制的组件方式。状态被存储在DOM中,而不是在组件状态中(注意我们用this.curriculum 来访问上传的文件,而没有触及state

我知道你在想什么--除了这些基本的东西,一定有一个库可以简化所有这些表单处理的东西,并自动进行验证、错误处理等,对吗?有一个很好的,Formik