Reactjs入门官方文档(八)【forms】

表单

译自reactjs官方文档
HTML 表单元素与 React 中的其他 DOM 元素有所不同,因为表单元素自然地保留了一些内部状态。例如,这个纯 HTML 表单接受一个单独的 name:

<form>
  <label>
    Name:
    <input type="text" name="name"/>
  </label>
  <input type="submit" value="Submit"/>
</form>

该表单和 HTML 表单的默认行为一致,当用户提交此表单时浏览器会打开一个新页面。如果你希望 React 中保持这个行为,也可以工作。但是多数情况下,用一个处理表单提交并访问用户输入到表单中的数据的 JavaScript 函数也很方便。实现这一点的标准方法是使用一种称为“受控组件(controlled components)”的技术。

受控组件(Controlled Components)s

在HTML 中,像<input><textarea><select> 这些form elements 通常保留它们自己的状态并根据用户输入来更新。在React 中,可变状态(mutable state)通常保存在组件的状态属性中(state property of components),并且只能由setState() 更新。

我们可以结合两方面来使React state 成为 “单一数据源原则”(single source of truth)。然后React 组件渲染form 同时也能控制后续的用户的输入。一个input 表单元素的值通过React 这种方式控制称为“受控组件”(controlled component)。

例如,如果我们想要在之前例子提交之前输出name,我们可以这样写一个form 作为controlled component:

class NameForm extends Component {
  constructor(props){
    super(props)
    this.state = {
      value : ''
    }

    this.handleChange = this.handleChange.bind(this)
    this.handleSubmit = this.handleSubmit.bind(this)
  }

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

  handleSubmit(event){
    alert('A name was submitted: ' + this.state.value)
    event.preventDefault()
  }

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

在CodePen 上尝试

由于value 特性(attribute)设置在form element,将总是展示this.state.value 这个值,使React state 成为同一数据理念(the source of truth)。由于handleChange 总是随着每一次按键而运行去更新React state,展示的值也总是随着用户的键入而更新。

对于controlled component,每一次状态改变(state mutation)总是有相应的句柄处理函数(handler function)。这能更直接的修改和验证用户的输入。例如,如果我们想强制将每一个输入都变成大写,我们可以如下修改handleChange

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

textare 标签

在 HTML 中,<textarea> 元素通过它的子节点定义了它的文本值:

<textarea>
  Hello there, this is some text in a text area
</textarea>

在React 中,<textarea> 通过使用value 特性(attribute)来替代。这种方式使用<textarea> 在写法上非常类似form 使用单行输入(single-line input):

class EssayForm extends Component {
  constructor(props){
    super(props)
    this.state = {
      value : 'Please write an essay about your favourite DOM element'
    }
    this.handleChange = this.handleChange.bind(this)
    this.handleSubmit = this.handleSubmit.bind(this)
  }

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

  handleSubmit(event){
    alert('An essay was submitted: ' + this.state.value)
    event.preventDefault()
  }

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

注意this.state.value 是在构造函数(constructor)中被初始化,所以这个文本域(text area)是以这里的文本为默认值的。

select 标签

在 HTML 中,<select> 创建了一个下拉列表。例如,这段 HTML 创建一个下拉的口味(flavors)列表:

<select>
  <option value="grapefruit">Grapefruit</option>
  <option value="lime">Lime</option>
  <option value="coconut" selected>Coconut</option>
  <option value="mango">Mango</option>
</select>

注意到由于selected 特性(attibute),Coconut 选项是初始化被选中的。在React 中通过在根select 标签上使用value特性(attribute)来替代使用selected 特性(attibute)。这对于controlled component 来说更方便,因为你只需要更新这一个位置就可以了。例如:

class FlavorForm extends Component {
  constructor(props){
    super(props)
    this.state = {
      value: 'coconut'
    }

    this.handleChange = this.handleChange.bind(this)
    this.handleSubmit = this.handleSubmit.bind(this)
  }

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

  handleSubmit(event){
    alert('Your favourite flavor is: ' + this.state.value)
    event.preventDefault();
  }

  render(){
    return (
      <form onSubmit={this.handleSubmit} >
        <label>
          Pick your favourite La Croix flavor
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
        </label>
        <input type="submit" value="Submit"/>
      </form>
    )
  }
}

在CodePen 上尝试

总的来说,这使得<input type="text><textarea> <select>的使用非常相似-它们都可以通过接受一个value 来实现controlled component。

处理多个输入元素

当你需要处理多个controlled input elements,你可以添加一个name 特性(attibute)到每一个element,并且让句柄函数(handler function)根据event.target.name 的值去选择做什么。

例如:

class Reservation extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    }

    this.handleInputChange = this.handleInputChange.bind(this)
  }

  handleInputChange(event) {
    const target = event.target
    const value = target.type === 'checkbox' ? target.checked : target.value
    const name = target.name

    this.setState({
      [name]: value
    })
  }

  render() {
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    )
  }
}

在CodePen 上尝试

注意我们如何使用ES6computed property name语法更新state key 响应给定的input name:

this.setState({
  [name]: value
})

这段代码等价于 ES5 代码:

var partialState = {}
partialState[name] = value
this.setState(partialState)

此外,由于setState()自动将部分状态合并到当前状态,所以我们只需要调用更改的部分。

受控组件的替代方案

有时使用controlled component 是非常令人厌烦的,因为你必须写事件句柄(event handler)为每一次你的数据改变和通过React component 来传递输入状态(input state)。尤其是在你改变之前的代码到React 或者在非React(non-React)库中使用React。在这些情况下,你可能想要符合uncontrolled components,一个替代实现input form 的技术。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值