React—表单及事件处理

表单

提到React中表单及事件处理,就不得不先介绍一下控组件与非受控组件的概念。

在HTML中,表单元素与其他元素最大的不同是它自带值或数据,而且在我们的应用中,只要是有表单出现的地方,就会有用户输入,就会有表单事件触发,就会涉及的数据处理。

在我们用React开发应用时,为了更好地管理应用中的数据,响应用户的输入,编写组件的时候呢,我们就会运用到受控组件与非受控组件这两个概念。

React推荐我们在绝大多数情况下都使用受控组件。这样可以保证表单的数据在组件的state管理之下,而不是各自独立保有各自的数据。

受控与非受控组件 Controlled & Uncontrolled

受控组件:

一般涉及到表单元素时我们才会使用这种分类方法。受控组件的值由props或state传入,用户在元素上交互或输入内容会引起应用state的改变。在state改变之后重新渲染组件,我们才能在页面中看到元素中值的变化,假如组件没有绑定事件处理函数改变state,用户的输入是不会起到任何效果的,这也就是“受控”的含义所在。

非受控组件: 类似于传统的DOM表单控件,用户输入不会直接引起应用state的变化,我们也不会直接为非受控组件传入值。想要获取非受控组件,我们需要使用一个特殊的ref属性,同样也可以使用defaultValue属性来为其指定一次性的默认值。

来看具体的例子:

// 受控组件
class ControlledInput extends React.Component {
  constructor() {
    super()
    this.state = {value: 'Please type here...'}
  }

  handleChange(event) {
    console.log('Controlled change:',event.target.value)
    this.setState({value: event.target.value})
  }

  render() {
    return (
      <label>
        Controlled Component:
        <input type="text"
               value={this.state.value}
               onChange={(e) => this.handleChange(e)}
        />
      </label>
    )
  }
}

// 非受控组件
class UncontrolledInput extends React.Component {
  constructor() {
    super()
  }

  handleChange() {
    console.log('Uncontrolled change:',this.input.value)
  }

  render() {
    return (
        <label>
          Uncontrolled Component:
          <input type="text"
                 defaultValue='Please type here...'
                 ref={(input) => this.input = input}
                 onChange={() =>this.handleChange()}
          />
        </label>
    )
  }
}

ReactDOM.render(
  <div>
    <UncontrolledInput />
    <ControlledInput />
  </div>
  ,document.getElementById('root'))

通常情况下,React当中所有的表单控件都需要是受控组件。但正如我们对受控组件的定义,想让受控组件正常工作,每一个受控组件我们都需要为其编写事件处理函数,有的时候确实会很烦人,比方说一个注册表单你需要写出所有验证姓名电话邮箱验证码的逻辑,当然也有一些小技巧可以让同一个事件处理函数应用在多个表单组件上,但生产开发中并没有多大实际意义。更有可能我们是在对已有的项目进行重构,除了React之外还有一些别的库需要和表单交互,这时候使用非受控组件可能会更方便一些。

表单元素

我们在组件中声明表单元素时,一般都要为表单元素传入应用状态中的值,可以通过state也可以通过props传递,之后需要为其绑定相关事件,例如表单提交,输入改变等。在相关事件触发的处理函数中,我们需要根据表单元素中用户的输入,对应用数据进行相应的操作和改变,来看下面这个例子:

class ControlledInput extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      value: ""
    }
  }

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

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

ReactDOM.render(<ControlledInput />,document.getElementById('root'))

受控组件的输入数据是一直和我们的应用状态绑定的,在上面这个例子中,事件处理函数中一定要有关state的更新操作,这样表单组件才能及时正确响应用户的输入,可以把setState语句注释掉来试验一下。

textarea:

HTML

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

JSX

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

这里需要强调一下,JSX中使用的和HTML标签同名的元素并不等同于原生的HTML标签,这只是React内部抽象出来的一种标签的写法,只是看起来一样而已,下面就介绍一下表单元素中,JSX和HTML不一样的,需要注意的地方。

在HTML中,textarea标签当中的内容都是在其开闭合标签之间的子节点当中的。而在JSX中,为了统一,textarea也可以定义一个名为value的属性,用来传入应用状态中的相关值。

select

HTML

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

JSX

<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>

select也是一样,注意这里的写法,同样我们可以为JSX当中的select标签定义value属性,与应用状态中相关数据值相同的option将会被默认选中。

使用受控组件和非受控组件都是有响应的适用场景的,就拿input来讲,比方说它是一个搜索框,我们需要在应用中实现根据搜索框内容输入异步返回相关搜索建议的功能,那么此处的input就应该是受控组件。而假如它是Todo应用中用来添加新事项的输入框,我们就没有特别的理由需要实时获取其中的数据,只需要在添加事项的事件触发时获取输入框中的值即可,这个地方就可以使用非受控组件。

事件

HTML

<button onclick="activateLasers()">
Activate Lasers
</button>

JSX

<button onClick={activateLasers}>
Activate Lasers
</button>

React元素的事件属性几乎与HTML中的事件相关属性相同,不过在React当中,事件相关的属性是以小驼峰的方式命名的。在这里还是要强调一下,React元素中的事件处理也是React内部的抽象封装,这里只是说,我们在JSX中写出来,看上去差不多,并不代表这是HTML原生的事件属性

// 手动绑定
this.handleClick = this.handleClick.bind(this);
// 箭头函数自动绑定
handleClick = () => {
    console.log('this is:', this);
  }

新版本的React中,我们可以通过类和函数声明React组件,在这两种形式的声明当中,我们都可以为其定义事件处理函数,函数定义的组件只需要在其方法内部再定义事件触发的函数即可;而如果是类声明组件,类定义组件中的自定义方法默认是没有绑定this的,因此加入我们需要在事件处理函数中调用this.setState一类的方法,就必须要手动将this绑定在相应的事件处理函数上。

代码示例:

class ControlledInput extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      value: ""
    };
    this.handleChange = this.handleChange.bind(this);
  }

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

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

ReactDOM.render(<ControlledInput />,document.getElementById('root'))

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏强仔仔

JQuery之内置函数响应事件

今天给大家介绍一下on函数中events的种类和用法。 具体我把它分为:键盘事件,鼠标事件,input事件,还有一个是基础事件(例如:滚动,界面大小变化等等之类...

1826
来自专栏从零开始学 Web 前端

从零开始学 Web 之 BOM(二)定时器

多次点击“摇起来”按钮的时候,timeId 的值会有多个,而停止的时候,只会清理最后一个值,其他的值对应的定时器没有清理。

981
来自专栏Google Dart

AngularDart Material Design 选项卡 顶

注意:为了获得高质量的用户体验,选项卡条的用户必须将焦点设置为新显示的内容,以便1)选项卡不保留焦点样式,2)屏幕阅读器可以计算已更改的内容。

1062
来自专栏无原型不设计

简单三步实现banner的轮播效果

目前有很多人使用Axure做轮播效果,步骤略复杂了些。这里,抛开其他设计原型不说,只说说banner图片轮播,三步教你实现轮播效果,我用的原型图软件是Mockp...

35410
来自专栏肖蕾的博客

解决安卓中XML文件声明高度 宽度无效的问题

1023
来自专栏HTML5学堂

CSS选择器优先级

HTML5学堂:CSS优先级所谓优先级是指CSS样式在浏览器中被解析的先后顺序。 CSS选择器的优先级:id > class > tagname。具体我们来看看...

2843
来自专栏Java帮帮-微信公众号-技术文章全总结

与Ajax同样重要的jQuery(2)

练习9: ² 点击button 打印radio checkbox select 中选中项的值 <script type="text/javascript" sr...

3005
来自专栏雪地二货笔记库

vue学习笔记9-监听属性-watch

这样就可以实现绑定 而且他后面也有很多功能,比如.lazy,惰性更新,只有焦点离开才会更新

621
来自专栏静晴轩

jQuery VS JavaScript原生API

如今技术日新月异,各类框架库也是层次不穷。即便当年漫山红遍的JQuery(让开发者write less, do more,So Perfect!!)如今也有被替...

4416
来自专栏水击三千

浅谈JavaScript的事件(事件模拟)

  事件经常由操作或者通过浏览器功能触发,通过JavaScript也可以触发元素的事件。通过JavaScript触发事件,也称为事件的模拟。 DOM中事件模拟 ...

2717

扫码关注云+社区