React如何实现其双向数据绑定?

时间:2018-10-20 01:29:00

标签: reactjs two-way-binding

我已经看到examples展示了如何在React中实现双向绑定,但是没有一个解释该功能在内部的实际功能。

codepen example中摘自React网站,如果您注释掉第11行:

handleChange(event) {
  // this.setState({value: event.target.value});
}

您将注意到即使用户直接修改输入框后,视图也不会以与数据模型不一致的方式进行更新,从而注意到React如何实施2向绑定。但是它是怎么做到的?

鉴于event.target.value的输入方式是用户刚刚在handleChange范围内输入的,但是在视图中仍然为空,这意味着该值有时已由React重置。另外,它不是将值简单地重置为空,而是根据最新的数据模型,可以通过对代码进行以下更改来进行测试:

constructor(props) {
  super(props);
  this.state = {value: ''};

  this.handleChange = this.handleChange.bind(this);
  this.handleSubmit = this.handleSubmit.bind(this);

  this.counter = 0;
}

handleChange(event) {
  if (this.counter < 3) {
    this.setState({value: event.target.value});
    this.counter++;
  }
}

这一次,输入框会前三次更改,然后根据最后的模型状态重置。

我的猜测如下:

  1. HTML元素根据用户输入进行了修改。
  2. “ onchange”事件处理程序被触发。
  3. 状态未更新。
  4. 由于状态尚未更新,因此React将组件的缓存Virtual-DOM表示形式与用户刚刚更改的Real-DOM元素进行比较。
  5. React更新Real-DOM元素的属性,使其与其Virtual-DOM表示保持一致。

如果状态已更改,则缓存的Virtual-DOM表示将被“污染”,这将触发虚拟元素的重新呈现。但是,我在上面描述的其余流程中仍然适用,这意味着将不会创建新的HTML节点,而只会更新现有HTML节点的属性(假设元素类型为<input>,没有变化)。

关于此功能的内部机制,这是我的最佳猜测。如果我错了,请告诉我,如果真的错了,那么问题的真正答案是什么。

谢谢!

2 个答案:

答案 0 :(得分:1)

这是一个简单的问题,我会尽力而为,如果有人发现我的回答有任何错误,请指出来,我将很乐意输入更正内容!挖掘React源代码,这就是我想出的东西:

1-修改了HTML,并在DOM中调用了一个事件

2-React在EventPropoagators.js内将事件/综合事件分派排队

3-事件按顺序出队(此事件对状态没有影响)

4-在事件循环结束时,react使用restoreTarget来还原受控组件以表示React Controlled Component.js中的状态:

  

用于在更改事件触发后恢复受控状态。

     

我们在事件循环结束时执行此转换,以便我们    总是在这里收到正确的光纤

这就是魔术发生的地方。 restoreTarget是组件的state,因此react此时会触发常规的render()重绘restoreTarget,我想这会通过标准的virtual-DOM与real- DOM协调算法。

根据您的示例,执行handleChange()(有或无状态更改)之后,将重绘restoreTarget并呈现一个组件,该组件准确地表示count = 3当时的状态。

答案 1 :(得分:0)

我将通过一个示例展示React的两种绑定方式。 设置一个React应用程序

App.js

import React, { Component } from 'react';
import './App.css';
import Person from './Person/Person';


class App extends Component {

  state = {
    persons: [
      {
        name: "VK",
        age: 29
      },
      {
        name: "HK",
        age: 28
      }
    ]
  }

  nameChangedHandler = (event) => {
    this.setState(
      {
        persons: [
          {
            name: "VK",
            age: 29
          },
          {
            name: event.target.value,
            age: 28
          }
        ],
        groupName: "Vishita"
      }
    );
  }

  render() {
    return (
      <div className="App">
        <h1>Vinit Khandelwal</h1>
        <p>And here is my resume</p>
        <Person 
        name={this.state.persons[0].name} 
        age={this.state.persons[0].age} />
        <Person 
        name={this.state.persons[1].name} 
        age={this.state.persons[1].age} 
        changed={this.nameChangedHandler} >Hobby: Shopping</Person>
      </div>
    );
  }
}

export default App;

Person> Person.js

import React from 'react';

const person = (props) => {
    return (
        <div>
            <p>I am {props.name}. I am {props.age} years old!</p>
            <p onClick={props.click}>{props.children}</p>
            <input type="text" onChange={props.changed} value={props.name} />
        </div>
    );
}

export default person;

此示例通过定义一个函数并调用该函数,传递事件并使用事件的值来展示React中的两种方式绑定。