ReactJS实用技巧(2):从新人大坑——表单组件来看State
不太清楚有多少初学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组件写法如下:
var Test = Rreact.createClass({
getInitialState: function() {
return {value: ''};
},
render: function({
return (<input type='text' value={this.state.value} onChange={this.handlerChange} />);
}),
handlerChange: function(event) {
var newValue = event.target.value;
this.setState({value: newValue});
}
});
上例中,我们监听了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)下所有的页面更新都是由这个方法来触发的。
var AddNum = React.createClass({
getInitialState: function() {
return {number: 0};
},
render:function() {
return (<span onClick={this.handlerClick}>{this.state.number}</span>);
},
handlerClick: function() {
var newNum = this.state.number;
newNum++;
this.setState({number: newNum});
}
});
上例中,这个组件创建了一个span元素,值为0。当我们每次点击该元素时数字便会加一。
解读分析下代码,首先我们通过getInitialState申明了该组件的state,包含一个number属性,初值为0。
在handlerClick的事件里我有一个"多余"的步骤,明明可以简化写成:
this.setState({number: ++this.state.number});
而我先用一个中间变量newNum保存了state里的number属性值,在newNum的基础上更改。
这里就是有关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就会触发组件的一次更新。在实际开发中通常用在下面这种情况:
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属性。
感谢您的浏览,希望有所帮助。
ReactJS实用技巧(2):从新人大坑——表单组件来看State的更多相关文章
- reactjs入门到实战(八)----表单组件的使用
表单组件支持几个受用户交互影响的属性: value,用于 <input>.<textarea> 组件. checked,用于类型为 checkbox 或者 radio 的 &l ...
- 【form】 表单组件说明
form表单组件 1)将form组件内的用户输入的<switch/> <input/> <checkbox/> <slider/> <radio/ ...
- 通过html()的方法获取文本内容, form表单组件显示的值与获取到的值不一致的问题
我在通过 html()获取对应节点的内容,发现一个问题,获取到的 form表单组件的内容值是初始加载的值,而不是经过用户修改后的值.例如页面加载时组件<input type="text ...
- 如何实现Ant design表单组件封装?
目标:自己实现一个antd表单组件 先看下Ant Design官网上给出的表单组件用法: import React, { Component } from 'react' import { Form, ...
- django基础之day09,创建一个forms表单组件进行表单校验,知识点:error_messages,label,required,invalid,局部钩子函数,全局钩子函数, forms_obj.cleaned_data,forms_obj.errors,locals(), {{ forms.label }}:{{ forms }},{{ forms.errors.0 }}
利用forms表单组件进行表单校验,完成用户名,密码,确认密码,邮箱功能的校验 该作业包含了下面的知识点: error_messages,label,required,invalid,局部钩子函数,全 ...
- 使用iview 的表单组件验证 Upload 组件
使用iview 的表单组件验证 Upload 组件 结果: 点击提交按钮, 没有填的form 项, 提示错误, 当填入数据后提示验证成功 代码: <template> <div id ...
- 文档驱动 —— 表单组件(五):基于Ant Design Vue 的表单控件的demo,再也不需要写代码了。
源码 https://github.com/naturefwvue/nf-vue3-ant 特点 只需要更改meta,既可以切换表单 可以统一修改样式,统一升级,以最小的代价,应对UI的升级.切换,应 ...
- 文档驱动 —— 表单组件(六):基于AntDV的Form表单的封装,目标还是不写代码
开源代码 https://github.com/naturefwvue/nf-vue3-ant 也不知道大家是怎么写代码的,这里全当抛砖引玉 为何封装? AntDV非常强大,效果也非常漂亮,功能强大, ...
- ReactJS实用技巧(1):JSX与HTML的那些不同
在项目中使用ReactJS也已经有大半年了,收获很多也踩过不少坑.不想把这个系列写成抄书似的罗列,旨在总结些常用的技巧及常见的坑,以帮助初心者快速入门,想系统学习的同学还是多阅读文档. JSX本质上与 ...
随机推荐
- ubuntu下配置时间同步NTP
1参考文献: 1.鸟哥的Linux私房菜:第十五章.时间服务器: NTP 服务器(强烈建议看完) 2.http://www.crsay.com/wiki/wiki.php/server/centos/ ...
- C# 引用的程序集没有强名称
首先查一下什么是强名称程序集,见百度百科帖子:http://baike.baidu.com/view/1145682.htm简单来说,就是为了解决Windows Dll Hell问题的,即不同公司开发 ...
- 浅析C#中的Attribute
原文地址:http://www.cnblogs.com/hyddd/archive/2009/07/20/1526777.html 一.什么是Attribute 先看下面的三段代码: 1.自定义Att ...
- 解决Win10无法安装.Net Framework 3.5,错误代码0x800F081F
重新安装了一遍Win10,但是不知怎的无法安装.net framework 3.5,即便是下载离线安装包也没法用. 网上有人说需要使用win10的ISO文件,个人感觉太麻烦,在这里分享一个很方便的操作 ...
- MySQL优化—工欲善其事,必先利其器(2)
上一篇文章简单介绍了下EXPLAIN的用法,今天主要介绍以下几点内容: 慢查询日志 打开慢查询日志 保存慢查询日志到表中 慢查询日志分析 Percona Toolkit介绍 安装 pt-query-d ...
- VS创建工程出错解决方案
今天在用VS2010创建工程时出现错误:“ 此模板尝试加载组件程序集 “NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, Pu ...
- 1.数据结构&算法的引言+时间复杂度
一.什么是计算机科学? 首先明确的一点就是计算机科学不仅仅是对计算机的研究,虽然计算机在科学发展的过程中发挥了重大的作用,但是它只是一个工具,一个没有灵魂的工具而已.所谓的计算机科学实际上是对问题.解 ...
- 让sublime text3支持Vue语法高亮显示[转]
1.准备语法高亮插件vue-syntax-highlight. 下载地址:https://github.com/vuejs/vue-syntax-highlight 下载页面并下载: 解开压缩包vue ...
- BZOJ 1076 奖励关 状态压缩DP
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1076 题目大意: 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里, ...
- swift的类型约束
关键词: 类型与功能绑定.类型指定.访问控制. 类型约束的本质: 1.是否强制指定具有某些特征的类型:看类型构造器的定义本身是否对类型有约束: 2.访问控制:类型构造器的功能分为通用功能和约束功能: ...