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

Posted

技术标签:

【中文标题】React 如何实现它的双向数据绑定?【英文标题】:How does React implement its two-way data binding? 【发布时间】:2019-03-24 21:29:15 【问题描述】:

我已经看到 examples 展示了如何在 React 中实现双向绑定,但没有人解释此功能实际上是如何在内部发挥作用的。

在这个来自 React 网站的 codepen example 中,如果你注释掉第 11 行:

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

您会注意到 React 如何通过确保视图不会以与数据模型不一致的方式更新来强制执行 2-way 绑定,即使在用户直接修改输入框之后也是如此。但它是如何做到的呢?

考虑到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++;
  

这一次,输入框改变了前三次,然后根据最后一个模型状态重置。

我的猜测如下:

    html 元素根据用户输入进行修改。 “onchange”事件处理程序被触发。 状态未更新。 由于状态未更新,React 将组件的缓存 Virtual-DOM 表示与用户刚刚更改的 Real-DOM 元素进行比较。 React 更新 Real-DOM 元素的属性,使其与其 Virtual-DOM 表示一致。

如果状态发生了变化,那么缓存的 Virtual-DOM 表示会被“弄脏”,这会触发虚拟元素的重新渲染。但是,我上面描述的其余流程仍然适用,这意味着不会创建新的 HTML 节点,只会更新现有节点的属性(假设元素类型,例如 &lt;input&gt;,没有t改变)。

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

谢谢!

【问题讨论】:

【参考方案1】:

这是一个巧妙的问题,我会尽力而为,如果有人在我的回答中发现任何错误,请指出,我很乐意编辑更正!挖掘 React 源代码是我想出的:

1 - 修改 HTML 并在 DOM 中调用事件

2 - React 将EventPropoagators.js 内的事件/合成事件调度排队

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

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

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

我们在事件循环结束时执行此转换,以便我们 始终在此处接收正确的光纤

这就是魔法发生的地方。 restoreTarget 是一个组件的 state,因此此时 react 会触发一个常规的 render() 以重绘 restoreTarget,我想这将通过它的标准虚拟 DOM 与真实 DOM 协调算法。

根据您的示例,handleChange() 被执行(有或没有状态更改),然后重绘restoreTarget 并呈现一个组件,该组件准确表示count = 3 所在时刻的状态。

【讨论】:

很遗憾,您的链接已损坏,仅提供 404。【参考方案2】:

我将通过一个示例展示 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 中的两种绑定方式:定义函数和调用函数,传递事件和使用事件的值。

【讨论】:

以上是关于React 如何实现它的双向数据绑定?的主要内容,如果未能解决你的问题,请参考以下文章

jquery怎么实现双向数据绑定

在react中实现一个简单双向数据绑定

React 实现数据双向绑定 事件的绑定以及传参 获取表单值的两种方法

Vue3的双向绑定是如何实现的

Vue,和React,实现的双向数据绑定效果

Vue双向绑定原理,教你一步一步实现双向绑定