不太清楚有多少初学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

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

  1. 封装react antd的form表单组件

    form表单在我们日常的开发过程中被使用到的概率还是很大的,比如包含了登录.注册.修改个人信息.新增修改业务数据等的公司内部管理系统.而在使用时这些表单的样式如高度.上下边距.边框.圆角.阴影.高亮等 ...

  2. 微信小程序-表单组件

    button 按钮 注:button-hover 默认为{background-color: rgba(0, 0, 0, 0.1); opacity: 0.7;} 示例代码: /** wxss **/ ...

  3. 实现Ant Design 自定义表单组件

    Ant Design 组件提供了Input,InputNumber,Radio,Select,uplod等表单组件,但实际开发中这是不能满足需求,同时我们希望可以继续使用Form提供的验证和提示等方法 ...

  4. Django form表单 组件

    目录 Django form表单 组件 Form 组件介绍 普通方式手写注册功能 使用form组件实现注册功能 Form 常用字段与插件 常用字段(必备) 字段参数(必备) 内置验证(必备) 自定义效 ...

  5. Vue 2.x折腾记 - (17) 基于Ant Design Vue 封装一个配置式的表单组件

    前言 写了个类似上篇搜索的封装,但是要考虑的东西更多. 具体业务比展示的代码要复杂,篇幅太长就不引入了. 效果图 2019-04-25 添加了下拉多选的渲染,并搜索默认过滤文本而非值 简化了渲染的子组 ...

  6. Vue组件之自定义表单组件

    今天又看了一遍vue的文档,记得之前学习的时候,官方文档中有提过,v-model指令是一个语法糖,做两件事,一个是给表单控件元素绑定value,第二个是当输入时更新绑定的值,不过后来在"表单 ...

  7. Form( 表单) 组件

    本节课重点了解 EasyUI 中 Form(表单)组件的使用方法, 这个组件不依赖于任何组件.一. 加载方式表单组件只能在 JS 区域设置,首先定义一张表单.<form id="box ...

  8. 「小程序JAVA实战」小程序的表单组件(25)

    转自:https://idig8.com/2018/08/18/xiaochengxujavashizhanxiaochengxudebiaodanzujian25/ 来说下 ,小程序的基础组件.源码 ...

  9. 第二百二十一节,jQuery EasyUI,Form(表单)组件

    jQuery EasyUI,Form(表单)组件 学习要点: 1.加载方式 2.属性列表 3.事件列表 4.方法列表 本节课重点了解 EasyUI 中 Form(表单)组件的使用方法,这个组件不依赖于 ...

随机推荐

  1. Linux下C程序内存泄露检测

    在linux下些C语言程序,最大的问题就是没有一个好的编程IDE,当然想kdevelop等工具都相当的强大,但我还是习惯使用kdevelop工具,由于没有一个习惯的编程IDE,内存检测也就成了在lin ...

  2. win10搭建FTP服务器

    下面就给大家讲解Win10搭建FTP服务器的详细操作方法. 1.首先,我们在Cortana中搜索控制面板并进入: 2.在控制面板-程序中,点击启用或关闭Windows功能: 3.在FTP服务器.Web ...

  3. vue项目各页面间的传值

    githut地址:https://github.com/liguoyong/vueobj1 一.父子之间主键传值:(主要是在父主件里的子主件传递参数,然后再子主件里用props接收) 例如Father ...

  4. 爬取代理IP,并判断是否可用。

    # -*- coding:utf-8 -*- from gevent import monkey monkey.patch_all() import urllib2 from gevent.pool ...

  5. 基于 Generator 和 Iterator 的惰性列表

    初识 Lazy List 如果有了解过 Haskell 的朋友,对下面的这些表达一定不陌生 repeat 1 -- => [1, 1, 1, 1, 1,...] cycle "abc& ...

  6. 二 python并发编程之多进程-理论

    一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行): egon在一个时间段内有很多任务要做:python备课的任务,写书的任 ...

  7. JavaScriptDate(日期)

    如何使用Date()方法获取当日的日期. getFullYear(): 使用getFullYear()获取年份. getTime(): getTime()返回1970年1月1日至今的毫秒数. setF ...

  8. day 71 Django基础六之ORM中的锁和事务

    Django基础六之ORM中的锁和事务   本节目录 一 锁 二 事务 三 xxx 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 锁 行级锁 select_for_update(no ...

  9. Java总结 - List实现类ArrayList&LinkedList

    本文是根据源码进行学习的,如果我有什么理解不对的地方请多指正,谢谢您 上面基本就是List集合类的类图关系了,图中省略掉了比如Cloneable等标记接口,那么List分别具体的主要实现类有:Arra ...

  10. linux-最最最最最常用的操作

    去除两个文件中相同的内容 比如我想把file1中不含文件file2的内容保留下来:(这个在抠一些内容的时候挺好用的) awk '{print $0}' file1 file2 |sort|uniq - ...