1、什么是双向绑定、为什么需要双向绑定?
本人是先入坑的vue,所以在开发时已经习惯了vue的自动双向绑定。
什么是双向绑定呢?
在没有前端框架之前的开发时光中,我们都是直接操作页面的DOM元素(element)的。将某个变量赋值到某个页面元素时都是一次性的操作,在此之后变量值的修改并不会影响页面元素的内容变化;而页面元素(比如input框)的内容变更以后,也不会使对应变量的值发生变化,我们需要通过document.getElementById()的方法获取到页面元素,然后再根据元素对象的value获取变化以后的值再手动处理。
在vue中,框架已经帮我们自动实现了双向绑定,任何一方(哪怕是页面上纯显示的)也会自动变化。(以下代码中,变量name的变化会直接反应到input框中,而input框中值得修改也会反向引起name变量的值变化。)
<!-- Vue中一个最简单的双向绑定示例 -->
<template>
<div>
<el-input v-model=“name” />
</div>
</template>
<script>
export default {
data() {
return {
name: "",
}
},
}
</script>
而到了react,发现并没有双向绑定的功能,有点懊糟。
NameShow.js
import React from 'react';
class NameShow extends React.Component {
myName = "" // 定义myName变量
render() {
return (
<div>
{/*尝试将myName变量绑定到input框上*/}
<input value={this.myName}/>
{/*获取myName,并直接显示在页面上*/}
<div>My Name Is {this.myName}</div>
</div>
)
}
}
export default NameShow
将以上组件引入APP中并添加到页面上启动,发现不仅无法双向绑定,甚至连修改input框的内容都没有任何反应,而且控制台有警告显示。大概的意思是value是只读的,值的修改必须通过onChange事件来修改。
![]()
所以添加一个onChange事件的handle方法handleChange以后再次启动。
NameShow.js
import React from 'react';
class NameShow extends React.Component {
myName = "" // 定义myName变量
handleChange = (event) => { // 此处需使用箭头函数,否则方法中的this将会识别为undefined
console.log(event.target.value)
this.myName = event.target.value
}
render() {
return (
<div>
{/*尝试将myName变量绑定到input框上*/}
<input value={this.myName} onChange={this.handleChange}/>
{/*获取myName,并直接显示在页面上*/}
<div>My Name Is {this.myName}</div>
</div>
)
}
}
export default NameShow
在输入框中输入内容以后,发现控制台有反应,正常拿到了修改以后的值,但是输入框和下面显示的内容却依旧没有变化。
![]()
![]()
2、React不支持双向绑定?非也
react并不是不支持双向绑定,而是双向绑定需要我们自己来实现。这时候就是react中的一个重要概念登场了——React State。
在菜鸟教程中的解释是这样的:React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
现在回到上面那个例子,进行一下改造,由使用类成员变量myName改为使用state中的myName变量。
NameShow2.js
import React from 'react';
class NameShow2 extends React.Component {
constructor(props) {
super(props);
this.state = { // 注意1:此处需先对state进行初始化,不然编译会报错
myName: "" // 注意2:此处需要将变量在state中进行定义,否则会报警告
}
}
handleChange = (event) => {
console.log(event.target.value)
// this.state.myName = event.target.value // 注意3:此处直接赋值是无效的,一定要使用this的setState方法
this.setState(
{myName: event.target.value}
)
}
render() {
return (
<div>
{/*尝试将myName变量绑定到input框上*/}
<input value={this.state.myName} onChange={this.handleChange}/>
{/*获取myName,并直接显示在页面上*/}
<div>My Name Is {this.state.myName}</div>
</div>
)
}
}
export default NameShow2
将以上组件引入APP中并添加到页面上启动,并在input框填入内容,发现下面的显示也同步改变了,并且控制台也有输出。
![]()
![]()
到此,一个简单的react双向数据绑定的流程就完成了。
3、小结
-
在react中要实现数据的双向绑定,需要通过state来实现,
根据菜鸟解释,react将每个组件都定义为状态机,通过state来改变和控制组件的状态。
-
使用state之前需要先初始化,并且在state中定义所需要用到的变量,
这个类似于vue中使用前先要在data部分定义变量。
(一般使用时可以不用预先定义变量,只有在变量绑定对象为<input> <textarea> <select>时才需要,具体内容可以参考react官网相关解释。)
-
直接对state进行赋值是无效的,需要使用setState方法来赋值,这样才能触发状态的改变,从而达到值传递的效果。
另外补充一点,在上述两个例子中都将handleChange方法都以箭头函数的方式进行定义,这是由于js的闭包导致的。
如果想将handleChange定义为普通方法,可以在构造函数中将this对象绑定到handleChange方法
constructor(props) {
super(props);
this.state = {
myName: ""
}
this.handleChange = this.handleChange.bind(this) // 将`this`对象绑定到`handleChange`方法
}