【09】react 之 表单组件

不太清楚有多少初学React的同学和博主当时一样,在看完React的生命周期、数据流之后觉得已经上手了,甩开文档啪啪啪的开始敲了起来。结果...居然被一个input标签给教做人了。

故事是这样的:首先你创建了一个input标签

var React = require(‘react‘),
    ReactDOM = require(‘react-dom‘);

var Test = React.render(function() {
    render: function() {
        return (<input type="text" />);
    }
});

ReactDOM.render(<Text />, document.querySelector(‘#container‘));

一切都是如此的轻松自然,接着由于需求你给input上设置了一个默认值:

<input value=‘123‘ type=‘text‘ />

突然你发现,唉我擦!输入框里的值不能改动了,删也删不掉。你以为电脑卡死了,刷新了几遍还是这样。然而把value删除就复原了,你不得不又返回去看文档。

原理:在React中表单组件分为约束组件和无约束组件两种。

  - 无约束组件,是指其value值不通过的props或者state来设置,仅由其自身来决定。表单组件的值的变化也不会被记录,只能通过找到DOM节点的方式来获取。

  - 约束组件,是React中推荐的表单的使用方式。表单组件的值并不是由其自身决定,而是通过父组件传递或者本身的state来控制。其内容的每次变化都会被保存,需要时仅需要通过this.state便能获取。

约束状态的input组件写法如下:

 class Test extends React.Component{
    constructor(props){
        super(props);
        this.handerChange = this.handerChange.bind(this);
    }
    handerChange(event){
        let newVal = event.target.value;
        console.log(newVal);
        this.setState({
            text:newVal
        });
    }
    render(){
        return (
            <input type="text" value={this.props.text} onChange={this.handerChange}/>
        );
    }
 }
  ReactDOM.render(<Test/>,document.getElementById(‘example‘))

上例中,我们监听了input的onchange事件,每一次内容的更改实际上是更改组件的state属性,通过state的变化来触发DOM元素的变化。

React之所以这么做的原因,是因为React其实为一个状态机,页面上所有的DOM元素的状态都需要被其所知所控制。

在继续理解表单组件之前,组件的state是必须被开发者所理解的。通常很多人喜欢将state与props一起讲解,这里博主认为通过state在表单组件的实际应用讲解可能更加直观。

State

每一本介绍React的书或文档都会把state和props放在一起详细的比较,其实最简单的说:state是组件内部用来控制组件状态的属性,props是组件之间用来通信的属性。

创建

state是通过名为getInitialState的生命周期函数创建的,其return出一个对象作为state值。如果你申明了该函数却没有返回值是会报错的。

创建之后,在组件内部的所有函数都可以用 this.state.属性名 来访问该属性。

修改

state的值并不是固定的,开发都通过在合适的时机改变它从而达到改变页面展示的目的。

改变state的唯一是this.setState,该方法可以说是整个React系统的"扳机",正常情况(除了直接操作DOM)下所有的页面更新都是由这个方法来触发的。

 class Test extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            text: "init text",
            }
        this.handerChange = this.handerChange.bind(this);
    }

    handerChange(event){
        let newVal = event.target.value;
        this.setState({
            text:newVal
        });
    }
    render(){
        return (
            <input type="text" value={this.state.text} onChange={this.handerChange}/>
        );
    }
 }
  ReactDOM.render(<Test/>,document.getElementById(‘example‘))

这里就是有关state很重要的一点:绝对不要直接更改state的值,只通过setState来改变。否则会因为多个地方多次对state更改,导致不统一。从而引发一些不必要的问题。

当state里有多个属性,如果需要更新某一个组件不用更新state里所有的属性,只更新需要的就好:

{name: ‘lilei‘, age: 25, sex: ‘男‘} //state

this.setState({name: ‘hanmeimei‘, sex: ‘女‘}); //state:{name: ‘hanmeimei‘, age: 25, sex: ‘女‘}

更新时机

既然setState是React的扳机,那它就不能随便在哪里都开枪。可能这部分东西需要对React的生命周期有一定掌握,许多文档和博客里都写得很详细。我这里就不再抄书了。

通常调用setState都是在人工触发的事件里,比如上例中的handlerClick。但总有需要自动触发的情形。生命周期主要分为创建、更新和销毁三个阶段。

  - 首先,在任何阶段的render函数里都是不可以调用setState来触发更新的。

  - 创建阶段,一般是在componentWillMount以及componentDidMount这两个生命周期函数中调用,前者表示React即将渲染真实DOM前的一个阶段,也是最后的修改state的机会。后者表示真实DOM已经渲染完成,在页面中能看到我们的组件了,这里再调用setState就会触发组件的一次更新。在实际开发中通常用在下面这种情况:(下面是es5的写法)

var Foo = React.createClass({
  getInitialState:function() {
    return {....};
  },
  render: function() {
    return (<..../>);
  },
  componentDIdMount: function(){
    AJAX {
      this.setState({....});    }
  }
});

大意就是首先创建出页面元素,在componentDidMount函数中发起ajax之类的请求,获取数据后通过setState更新页面将数据更新到页面中。

这样做的好处就是在请求较慢或者请求失败的情况下,页面不至于留白,影响用户体验。

  - 更新阶段,绝...对...不...要...在...这...个...阶...段...调...用。因为如果在该阶段任意一个生命周期函数中使用setState触发页面更新时,组件又会再次进入生命周期的更新阶段,这里会再次调用setState方法,然后进入死循环。

  - 销毁阶段,就更不用说了,组件都没得了,还更新个毛啊。

了解完了state,继续看input的无约束组件。

<input defaultValue="123" />

如果设置了defaultValue属性,该组件就是无约束组件。此时可以直接设置input的默认值,设置之后内容可以直接进行更改。缺点是这个属性貌似只能设置一次,重复设置无效。

如果你不想为约束组件编写如上那些繁琐的过程,React提供了简单的方法——mixin。

mixin

简单来说mixin是用来抽象某一功能的工具,将逻辑抽象出来,使其可以在多个组件里复用。除了自定义以外,官方已经封装了一系列的mixin组件,使用前需要引入react-with-addons文件。

var Form = React.createClass({
  mixins: [React.addons.LinkedStateMixin],
  getInitialState: function() {
      return {userName: ‘‘, passWord: ‘‘};
  },
  render: function() {
      return (<div>
          <form>
            <input type=‘text‘ valueLink={this.linkState(‘userName‘)} placeholder=‘用户名‘  />
            <input type=‘password‘ valueLink={this.linkState(‘passWord‘)} placeholder=‘密码‘ />
          </form>
        </div>);
  }
});

如上引入mixin组件后,只需要在input的特殊属性valueLink中调用this.linkState(‘属性名‘),之后每次对input内容的更改就会同步到组件state中同名的属性中。

其实LinkedStateMixin内部的实现跟我们Test那个示例组件里是一样的,看懂了那段代码就能理解这个mixin插件的内部原理了。

*虽然使用mixin可以简化书写流程,但是使用这种方式往数据流中添加定制功能时,复杂度会增加,建议只在特定场景下使用。传统的约束表单组件更加灵活。

下面介绍下其他表单组件的内容

Label

label元素是表单中很重要的一个部分,由于for在JavaScript中是一个保留字,所以在JSX中for属性更改为htmlFor。

<label htmlFor=‘name‘>姓名</label>

Textarea

与传统的HTML相比,在React中,textarea被修改为更像input的形式。

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

textarea的约束组件的使用方法与input一致,同时也可以使用同一个mixin。

<textarea valueLink={this.linkState(‘value‘)} />

使用defaultValue属性同样可以将textarea变为无约束组件。

<textarea defaultValue=‘请输入内容‘ />

Select

在React中select与textarea一样,相比HTML也作了一些修改,使它们操作起来更简便。

无约束组件:

<select defaultValue=‘B‘>
  <option value=‘A‘>AAA</option>
  <option value=‘B‘>BBB</option>
  <option value=‘C‘>CCC</option>
</select>

约束组件:

var SelectComponent= React.createClass({
  getInitialState: function() {
    return {option: ‘A‘};
  },
  render: function() {
    return (<select value={this.state.option} onChange={this.handlerChange}>
          <option value=‘A‘>A</option>
          <option value=‘B‘>B</option>
          <option value=‘C‘>C</option>
        </select>);
  },
  handlerChange: function(event) {
    this.setState({option: event.target.value});
  }

单选

约束组件:

var Radio = React.createClass({
  getInitialState: function() {
    return {gender: ‘男‘};
  },
    render: function() {
    return (<div>
          <input type=‘radio‘ name=‘gender‘ value=‘男‘ checked={this.state.sex == ‘男‘} onChange={this.handlerChange} />男
          <input type=‘radio‘ name=‘gender‘ value=‘女‘ checked={this.state.sex == ‘女‘} onChange={this.handlerChange} />女
        </div>);
  },
  handlerChange: function(event) {    this.setState({gender: event.target.value});
  }
});

设置单选的defaultChecked会使其变为无约束组件。

<input type=‘radio‘ defaultChecked=‘true‘ />

复选

约束组件:

var CheckBox = React.createClass({
  getInitialState: function() {
    return {basketBall: false, swim: false, sing: false};
  },
  render: function() {
    return (<div>          <p>爱好:</p>
          <input type=‘checkbox‘ checked={this.state.basketBall} value=‘basketBall‘ onChange={this.handlerChange} />篮球
          <input type=‘checkbox‘ checked={this.state.swim} value=‘swim‘ onChange={this.handlerChange} />游泳          <input type=‘checkbox‘ checked={this.state.sing} value=‘sing‘ onChange={this.handlerChange} />唱歌
        </div>);
  },
  handlerChange: function(event) {    var type = event.target.value,       checked = event.target.checked,       newState = {};    newState[type] = checked;    this.setState(newState);
  }
});

在handlerCheck函数中有一点要注意,我创建了一个中间变量newState。

handlerCheck: function(event) {  var type = event.target.value,     checked = event.target.value;  this.setState(type: checked); //state: {basketBall: false, swim: false, sing: false, type: true}
}

如果像上面的写法,type并不会作为变量,而是作为字符串解析。每当你在setState时遇到困难时,尝试中间变量,这方法百试不爽。

无约束组件:

<input type=‘checkbox‘ defaultChecked=‘true‘ />

多表单元素与change事件处理

在实际开发中通常有多个表单组件,为了使一个change处理器能处理所有的表单组件变化,可以使用bind方法来绑定类型。

var FormComponent = React.createClass({
  getInitialState: function() {
    return {name: ‘‘, gender: ‘男‘};
  },
  render: function() {
    return (<form>
          <input type=‘text‘ value={this.state.name} onChange={this.handlerChange.bind(this,‘name‘)} />
          <label htmlFor=‘male‘>男</label>
          <input id=‘male‘
              name=‘gender‘
              type=‘radio‘
              value=‘男‘
              checked={this.state.gender == ‘男‘}
              onChange={this.handlerChange.bind(this,‘gender‘)} />
          <label htmlFor=‘female‘>女</label>
          <input id=‘female‘
              name=‘gender‘
              type=‘radio‘
              value=‘女‘
              checked={this.state.gender == ‘女‘}
              onChange={this.handlerChange.bind(this,‘gender‘)} />
        </form>);
  },
  handlerChange: function(type, event) {
    var newState = {};
    newState[type] = event.target.value;
    this.setState(newState);
  }
});

表单是React初学者很容易踩的大坑,但是对表单组件的学习可以很快的理解state属性。

转载:http://www.cnblogs.com/ghost-xyx/p/5253567.html

时间: 2024-08-04 20:27:07

【09】react 之 表单组件的相关文章

小程序七:组件之表单组件

button 按钮组件. 属性名 类型 默认值 说明 size String default 有效值default, mini type String default 按钮的样式类型,有效值primary, default, warn plain Boolean false 按钮是否镂空,背景色透明 disabled Boolean false 是否禁用 loading Boolean false 名称前是否带 loading 图标 formType String 无 有效值:submit, r

deirective写form表单组件

directive 在使用隔离 scope 的时候,提供了三种方法同隔离之外的地方交互.这三种分别是 @ 绑定一个局部 scope 属性到当前 dom 节点的属性值.结果总是一个字符串,因为 dom 属性是字符串.& 提供一种方式执行一个表达式在父 scope 的上下文中.如果没有指定 attr 名称,则属性名称为相同的本地名称.= 通过 directive 的 attr 属性的值在局部 scope 的属性和父 scope 属性名之间建立双向绑定 但是当我们不使用隔离scope的时候,我们要能够

HTML表单组件

HTML表单组件 form标签里面的东西 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Form.html</title> 5 6 <meta name="keywords" content="keyword1,keyword2,keyword3"> 7 <meta name="description" content=&qu

常用表单 组件封装

1. 基本功能预览        2.基本功能 本次封装的表单组件,分为单行和2行 两种情况: 两种组件 都有设置图片lable.标题 (title).按提示(hint).文案(text).内容距边间距离(padding)这些通用功能: 其次,单行表单组件 还可以允许文本输入.设置标题(title),以及文案(text)/输入框  字体的大小和颜色. ... 总的来说,满足 android 开发过程中常见的表单情况. 3.基本使用 1. FormNormal 使用 <com.dzq.widget

vue动态生成表单组件vue-generate-form

项目地址 简介 Vue动态生成表单组件 可以根据数据配置表单 使用的UI库是iView 在Vue里 一般要用到什么组件或数据 都得提前声明 所以要根据数据来生成表单 只能使用Vue的render函数 要做这一个组件 其实并不难 看一下Vue官方示例 再找个UI组件库 差不多就能写出来 如果对项目有兴趣 可以fork或克隆项目 自行研究 有问题或BUG欢迎提issues 文档 在线DEMO 表单组件 Input 输入框 Button 按钮 Radio 单选框 Checkbox 多选框 Icon 图

React之表单

第一部分:表单基础 在React中,修改表单的唯一途径是使用setState方法.举例如下: class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); }

【Flutter学习】基本组件之基本表单组件

一,概述 表单时一个包含表单元素的区域. 表单元素允许用户输入内容,比如文本域,下拉列表,单选框,复选框等.常见的应用场景有:登录,注册,输入信息等. 表单里有两个重要的组件: Form:用来做整个表单提交使用 TextFormField:用来做用户输入.  正式向服务器提交数据前,都会对各个输入框数据进行合法性校验.但对每个TextField都分别校验很麻烦. 如果想清除一组TextfFiled的内容,一个个清除也很麻烦.所以,Flutter提供了一个Form widget,可以对输入框进行分

div模拟 select 或者 其他表单组件

1 <form action="" method="post"> 2 <div id="divselect"> 3 <cite>请选择特效分类</cite> 4 <ul> 5 <li><a href="javascript:;" selectid="1">导航菜单</a></li> 6 <li&

详解Bootstrap表单组件

表单常见的元素主要包括:文本输入框.下拉选择框.单选框.复选框.文本域.按钮等.下面是不同的bootstrap版本: LESS:  forms.less SASS:  _forms.scss bootstrap仅对表单内的fieldset.legend.label标签进行了定制 fieldset { min-width: 0; padding: 0; margin: 0; border: 0; } legend { display: block; width: 100%; padding: 0;