在React中关于表单分为两部分内容,受控组件和非受控组件。
4.7.1 受控组件
我们知道,在HTML中的表单元素是可以输入数据的(也可以进行删除),也就是有自己的可变状态。例如文本框,可以在文本框中输入内容,也可以进行删除,而输入的内容我们可以称之为可变的状态。而这个状态是有HTML表单元素自己维护的。
但是在React中,我们知道可变的状态通常保存在state中,并且只能通过setState方法来进行修改。
这时与HTML中的表单元素在状态的维护上产生了冲突。为了解决这个冲突,React将state与表单元素的值value绑定到一起,由state的值来控制表单元素的值。
所以我们将其值受到React控制的表单元素称之为受控组件。
import React,{Component}from 'react'
class App extends Component{
state={
num:10
}
handleChange=e=>{
this.setState({
num:e.target.value
})
}
render(){
return (
{this.state.num}
)
}
}
export default App
在这里,将React中state状态与文本框中的value属性进行了绑定,然后给文本框添加了一个onChange,当在文本框中输入值的时候,会调用handleChange方法,在这个方法中通过e.target.value获取文本框中输入的值,然后重新给了state,这时在div中展示的state中的num也发生了相应的变化。
下面再看几个受控组件的案例:
富文本框案例
富文本框的实现和文本框的实现基本上是一样的,代码如下所示:
import React,{Component}from 'react'
class App extends Component{
state={
content:'Hello'
}
handleChange=e=>{
this.setState({
content:e.target.value
})
}
render(){
return (
{this.state.content}
)
}
}
export default App
下拉框应用
import React,{Component}from 'react'
class App extends Component{
state={
city:'shanghai'
}
handleChange=e=>{
this.setState({
city:e.target.value
})
}
render(){
return (
{this.state.city}
)
}
}
export default App
在上面的代码中,定义的state中的city取值为'shanghai',并与select标签的value属性进行了绑定了,这时会默认显示’上海‘这一项。当选择下拉框中的不同的选项时,会执行onChange对应的handleChange方法,在该方法中获取用户选择的项的value值,然后重新赋值state.
复选框应用
import React,{Component}from 'react'
class App extends Component{
state={
isChecked:true
}
handleChange=e=>{
this.setState({
isChecked:e.target.checked
})
}
render(){
return (
复选框
)
}
}
export default App
注意,这里获取的是复选框的checked.
更新完复选框的状态后,想立即查看对应的状态值。
import React, { Component } from "react";
class ControlComponent extends Component {
state = {
isChecked: true,
};
handleChange = (e) => {
this.setState({ isChecked: e.target.checked }, () => {
console.log(this.state.isChecked);
});
};
render() {
return (
复选框
);
}
}
export default ControlComponent;
上面的代码,给setState方法添加了第二个参数,第二个参数是一个回调函数,当状态更新成功后,会立即调用
受控组件更新state流程
通过前面打的案例,这里可以总结出React受控组件更新state的流程
(1)可以通过在初始state中设置表单的默认值。
(2)给表单添加onChange,并且当表单中的值发生了变化时,会调用onChange所指定的函数。
(3) 在所对应的处理函数中通过合成事件对象获取到表单改变后的状态,并且更新对应的state.
(4)setState触发页面的重新渲染,完成表单中值的更新。
其实通过整个流程的分析,可以发现最开始表单中的数据来源于state,也就是将state绑定到表单上,这其实就是单向的数据绑定。然后,我们又通过onChange事件对应的方法将在表单中输入的新的数据又更新回了state中,这样就完成了双向数据绑定。
与原生表单相比,受控组件的模式确实复杂了很多,每次表单中数据变化时,都会执行上面这几步,但是对表单中的值进行一些特殊操作的时候会变得更加容易。
例如:下面的案例要求,在文本框中输入的值不能超过60
import React,{Component}from 'react'
class App extends Component{
state={
num:10
}
handleChange=e=>{
this.setState({
// 获取到用户在文本框中输入的值,如果超过60,对应的state的值为10,这时文本框中显示的还是10.
num:e.target.value>60?10:e.target.value
})
}
render(){
return (
{this.state.num}
)
}
}
export default App
表单处理优化
现在,我们思考一个问题,如果一个页面中需要的表单元素比较多,应该怎样进行处理呢?
如果还是按照前面的方式进行处理,那么需要写很多的方式。这样就比较麻烦了。所以,这里可以将多个表单元素的处理封装到一个方法中完成,但是问题是,在这个方法中需要处理不同的表单元素,那么应该怎样进行区分呢?
这时要考虑的问题,下面先看一下具体的实现步骤:
- 给表单元素添加name属性(用来区分是哪一个表单),名称与state相同(用来更新数据的)
- 根据表单内容来获取对应值
- 在change事件处理程序中通过 [name] 来修改对应的state.
通过具体的实现步骤:
可以发现,要想在方法中能够区分开所处理的表单元素,需要通过name属性来完成。
具体代码实现如下:
import React,{Component}from 'react'
class App extends Component{
state={
num:10,
content:'Hello',
city:'shanghai',
isChecked:true
}
handleChange=e=>{
// 获取当前的元素.
const target = e.target;
//判断元素的类型
const value=target.type==='checkbox'?target.checked:target.value;
console.log(value);
//获取name
const name=target.name;
this.setState({
[name]:value
})
}
render(){
return (
{this.state.num}
{this.state.content}
{this.state.city}
复选框
)
}
}
export default App
非受控组件
非受控组件,不在受状态state的控制。它需要借助于ref, 使用元素DOM方式获取表单元素值。
ref的作用就是用来获取DOM的,所以说这种方式是直接操作DOM的方式。
具体的实现步骤如下:
- 调用 React.createRef() 方法创建ref对象
- 将创建好的 ref 对象添加到文本框中
- 通过ref对象获取到文本框的值
代码演示如下所示:(单击按钮,获取文本框中的值)
import React,{Component}from 'react'
class App extends Component{
constructor(){
super()
//创建ref,将创建好的ref赋值给当前的this
this.txtRef= React.createRef()
}
getValue=()=>{
//获取文本框中的值(注意这里需要添加current)
console.log(this.txtRef.current.value)
}
render(){
return (
{/* 将创建好的ref与当前文本框关联起来 */}
)
}
}
export default App
学IT,上博学谷