# 双向数据绑定
## 第一种方法:重点推荐
对组件身上添加 ref属性,且设置值a。在setState功能中使用 this.refs.a就可以直接获取元素。
```javascript
<input ref="input" type="text" defaultValue={this.state.msg} onChange={this.changeValue.bind(this)} />
changeValue(event){
this.setState(()=>{
return {
msg:this.refs.input.value
}
})
}
```
## 第二种方法:
通过事件对象e传递 e.target.value直接 书写会有错误,[https://reactjs.org/docs/events.html#event-pooling。解决办法](https://reactjs.org/docs/events.html#event-pooling%E3%80%82%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95) 两种
1. 直接在setState方法外面,先把值存储好,再使用 这个值就可以,推荐
```javascript
changeValue(event){
var value = event.target.value;
this.setState(()=>{
return {
msg:value
}
})
}
```
2. 通过在setState方法外面,书写e.persist()方法,进行保护就可以。建议少用
```javascript
changeValue(event){
event.persist()
this.setState(()=>{
return {
msg:event.target.value
}
})
}
```
## 第三种方法
对组件添加id名称,获取元素的value值即可.最不推荐
```javascript
<input id="box" type="text" defaultValue={this.state.msg} onChange={this.changeValue.bind(this)} />
changeValue(event){
this.setState(()=>{
return {
msg:document.getElementById('box').value
}
})
}
```
# 下面为分析具体分析和操作
## 新建src/components/BridgeLink.js组件
BridgeLink.js准备一个输入框,以及一个私有数据,当用户在表单中输入数据,那么相应的私有数据也应该改变。
~~~
import React,{Component} from 'react'
export default class BridgeLink extends Component{
constructor(props){
super(props)
this.state={
msg:'你好'
}
}
render() {
return <div>
<input />
<span>{this.state.msg}</span>
</div>
}
}
~~~
我们给表单书写属性值绑定数据。
~~~
<input value={this.state.msg}/>
~~~
![](https://box.kancloud.cn/48ba930afd40ed67e9ce94ae1e9c173f_224x50.png)
# f12控制台
```
Warning: Failed prop type: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.
警告:失败的属性类型:您为没有“onchange”处理程序的表单字段提供了“value”属性。这将呈现只读字段。如果字段应该是可变的,请使用“defaultvalue”。否则,设置“onchange”或“readonly”。
```
这里的意思是如果期望表单书写value属性那么必须有onchange事件。
~~~
changeMsg(){
}
……
<input onChange={this.changeMsg.bind(this)} value={this.state.msg}/>
~~~
![](https://box.kancloud.cn/31bbe5f4dc52dd8ed98fbefe3fa6a804_899x189.gif)
我们发现在输入框不断的输入不会发生任何的改变。我们也明白了,React 默认不会直接对数据进行双向数据绑定。如果想要改变state的msg数据人能通过this.setState来改变数据。
# 将state中的msg数据修改为表单的值
> 我们要获取到表单的值如何获取?
> 有三种方法
> 1.通过React操作dom的方式 refs(推荐又简单又好做)
> 2.通过事件对象。通过e.target.value (次推荐)
> 3.通过ID 操作原生DOM来获取到表单的值(最low)
## 第一种
推荐使用其实和vue中的$refs很相似。通过`this.$refs.my`来获取元素.value来获取表
~~~
changeMsg(e){
this.setState((state,props)=>{
return {msg:this.refs.my.value}
})
}
……
<input ref="my" onChange={this.changeMsg.bind(this)} id="input" value={this.state.msg}/>
~~~
## 第二种
最麻烦,而且是有问题的,在使用时千万要小心,请按照步骤去做。
通过事件对象e传递 e.target.value直接 书写会有错误,[https://reactjs.org/docs/events.html#event-pooling](https://reactjs.org/docs/events.html#event-pooling)。解决办法 两种
~~~
changeMsg(e){
console.log(e.target.value)
}
……
<input onChange={this.changeMsg.bind(this)} value={this.state.msg}/>
~~~
![](https://box.kancloud.cn/1f7e12e014d959dd22da5cf2c361741b_901x234.gif)
~~~
changeMsg(e){
console.log(e.target.value)
this.setState({
msg:e.target.value
})
}
……
<input onChange={this.changeMsg.bind(this)} value={this.state.msg}/>
~~~
![](https://box.kancloud.cn/43f1379d5bed5814ab0e2fc38d2d90e9_918x206.gif)
看到上面的结果我们觉得是达到目的了。不过我们使用this.setState()的这种方法是直接操作的。还有另外一种写法
~~~
this.setState((state,props)=>{
return { msg: e.target.value}
})
~~~
我们来尝试一下直接报错
```
react-dom.development.js:506 Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property `target` on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist(). See https://fb.me/react-event-pooling for more information.
```
注意这种更改私有数据state的方法,许多人都在用。那么为什么它不可以呢?我们可以稍微的修改一下代码
~~~
changeMsg(e){
console.log(e.target.value)
this.setState((state,props)=>{
console.log(e.target)
// return { msg: e.target.value}
})
}
~~~
![](https://box.kancloud.cn/40cbd22ea2463f26be6529261ccf595a_1060x193.gif)
我们发现结果为null那么如何解决这个问题呢?
有两种办法
### 第一种解决办法
我们发现在this.setState的外面方问e.target.value居然有值,在this.setState内部竟然得不到值。我们可以在外面先把值保存起来,再去使用这个值,修改如下
~~~
changeMsg(e){
console.log(e.target.value)
var value = e.target.value
this.setState((state,props)=>{
return { msg: value}
})
}
~~~
![](https://box.kancloud.cn/45e3d4dc62348e8a9ac3a871aa0b12d0_912x190.gif)
### 第二种解决办法
这个解决办法是官方提供的,根据报错的提示中我们有发现它让我们使用event.persist(),来将事件对象一直保持。
其实React在this.setState方法体中它已经将事件对象重新进行修改。不过也提供了方法如果你不期望被修改一直保持,就需要使用上面的给出的event.persist();不过这种方法不常用。
~~~
changeMsg(e){
e.persist();
this.setState((state,props)=>{
return { msg: e.target.value}
})
}
~~~
## 第三种
~~~
changeMsg(){
console.log(document.getElementById('input').value)
}
……
<input onChange={this.changeMsg.bind(this)} id="input" value={this.state.msg}/>
~~~
![](https://box.kancloud.cn/32cf98970b88876d32cc4b9e4ea282cb_908x160.gif)
我们发现我们是可以取到表单的数据了。接下来就是将表单的值与私有数据的msg进行同步。
~~~
changeMsg(){
console.log(document.getElementById('input').value)
this.setState({
msg:document.getElementById('input').value
})
}
……
<input onChange={this.changeMsg.bind(this)} id="input" value={this.state.msg}/>
~~~
![](https://box.kancloud.cn/95df7041a5b2604603b650f109a15bd5_798x233.gif)
# 总结
对于React的双向数据绑定,重点掌握。
1.对于设置数据有两种操作方式`this.setState({})`和`this.setState((state,props)=>{ return {} })`两种都要知道,工作中的话,使用任意一种都可以,为了工作方便**建议掌握后者**,因为操作起来便利。
2.着重掌握`refs`操作dom的方式。
- webpack复习
- React基础
- 前端三大主流框架对比
- React中几个核心的概念
- React基础语法
- React JSX语法
- React组件
- 普通组件
- 组件通信-父向子传递
- 组件拆成单个文件
- 面向对象复习
- Class组件基础
- Class组件的私有状态(私有数据)
- 案例:实现评论列表组件
- 组件样式管理
- 组件样式分离-样式表
- CSS模块化
- 生命周期
- React组件生命周期
- Counter组件来学习组件生命周期
- 生命周期总结
- 生命周期案例
- React评论列表
- React双向数据绑定
- React版todolist
- 其它提高(了解)
- 组件默认值和数据类型验证
- 绑定this并传参的三种方式
- 祖孙级和非父子组件传递数据(了解)
- React路由
- 路由基础
- 动态路由
- 路由严格模式
- 路由导航定位
- 路由重定向
- 路由懒加载
- WolfMovie项目
- 项目初始化
- AntDesign使用
- 其它相关了解