# 雙向數據綁定
## 第一種方法:重點推薦
對組件身上添加 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}/>
~~~

# 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}/>
~~~

我們發現在輸入框不斷的輸入不會發生任何的改變。我們也明白了,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}/>
~~~

~~~
changeMsg(e){
console.log(e.target.value)
this.setState({
msg:e.target.value
})
}
……
<input onChange={this.changeMsg.bind(this)} value={this.state.msg}/>
~~~

看到上面的結果我們覺得是達到目的了。不過我們使用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}
})
}
~~~

我們發現結果為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}
})
}
~~~

### 第二種解決辦法
這個解決辦法是官方提供的,根據報錯的提示中我們有發現它讓我們使用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}/>
~~~

我們發現我們是可以取到表單的數據了。接下來就是將表單的值與私有數據的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}/>
~~~

# 總結
對于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使用
- 其它相關了解