React 源码中的依赖注入方法


Posted in Javascript onNovember 07, 2018

一、前言

依赖注入(Dependency Injection)这个概念的兴起已经有很长时间了,把这个概念融入到框架中达到出神入化境地的,非Spring莫属。然而在前端领域,似乎很少会提到这个概念,难道前端的代码就不需要解耦吗?前端的代码就没有依赖了?本文将以 React 的源码为例子,看看它是如何使用依赖注入这一设计模式的。

二、依赖注入的基本概念

在看代码之前,有必要先简单介绍一下依赖注入的基本概念。依赖注入和控制反转(Inversion of Control),这两个词经常一起出现。一句话表述他们之间的关系:依赖注入是控制反转的一种实现方式。另一种方式叫依赖查找(Dependency Lookup)。

在控制不反转的情况下,某个类如果依赖另一个类,它会自己来创建依赖:

class Person {
  eat() {
    const dinner = new Dinner('法国菜');
    console.log('开饭啦!,今晚自己做:', dinner.name);
  }
}

class Dinner {
  constructor(name) {
    this.name = name;
  }
}

假设一个人要吃饭,如果控制不反转,就需要自己来做,像上面的代码一样要自己new Dinner。

如果使用控制反转,吃什么就不用自己费脑子了,别人给我做好放到我面前,我直接吃就好!

class Person {
  eat(dinner) {
    console.log('开饭啦!,今晚有大厨给我做:', dinner.name);
  }
}

也就是说,不需要自己来创建依赖的对象了,由外部传入,这就是依赖注入!

三、React 中的依赖注入

众所周知,React 除了可以在浏览器运行外(ReactDOM),也可以制作 App 在手机端运行(ReactNative)。而两者有大量的代码都是可以共享的,这就是依赖注入的使用场景了。

我们来看下具体是如何注入的:

// ReactDOM.js
var ReactDefaultInjection = require('ReactDefaultInjection');
ReactDefaultInjection.inject();

// ReactNative.js
var ReactNativeDefaultInjection = require('ReactNativeDefaultInjection');
ReactNativeDefaultInjection.inject();

注入的位置都在框架代码最开始加载的位置。下面以 ReactDOM 为例子,详细讲解注入的逻辑。

先来看看需要注入的对象都有哪些,定义在 ReactInjection.js 这个文件当中:

var DOMProperty = require('DOMProperty');
var EventPluginHub = require('EventPluginHub');
var EventPluginUtils = require('EventPluginUtils');
var ReactComponentEnvironment = require('ReactComponentEnvironment');
var ReactEmptyComponent = require('ReactEmptyComponent');
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
var ReactHostComponent = require('ReactHostComponent');
var ReactUpdates = require('ReactUpdates');

var ReactInjection = {
 Component: ReactComponentEnvironment.injection,
 DOMProperty: DOMProperty.injection,
 EmptyComponent: ReactEmptyComponent.injection,
 EventPluginHub: EventPluginHub.injection,
 EventPluginUtils: EventPluginUtils.injection,
 EventEmitter: ReactBrowserEventEmitter.injection,
 HostComponent: ReactHostComponent.injection,
 Updates: ReactUpdates.injection,
};

module.exports = ReactInjection;

这里面每一个 injection 都是一个对象,对象内定义了一个或多个 inject 的方法来注入对应的内容。以ReactUpdates.injection为例子:

// ReactUpdates.js
var ReactUpdatesInjection = {
  injectReconcileTransaction: function (ReconcileTransaction) {
    ...
    ReactUpdates.ReactReconcileTransaction = ReconcileTransaction;
  },

  injectBatchingStrategy: function (_batchingStrategy) {
    ...
    batchingStrategy = _batchingStrategy;
  },
};

var ReactUpdates = {
  ...
  injection: ReactUpdatesInjection,
};

可以看到 ReactUpdates 依赖的ReactReconcileTransaction和batchingStrategy就是通过这 2 个方法注入进去的。

有了上面的内容,相当于定义好需要依赖的内容了。下一步就是创建具体的依赖内容,然后注入到需要的地方:

// ReactDefaultInjection.js
var ReactInjection = require('ReactInjection');
var ReactReconcileTransaction = require('ReactReconcileTransaction');
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');

...

function inject() {
  ...

  ReactInjection.Updates.injectReconcileTransaction(
    ReactReconcileTransaction
  );
  ReactInjection.Updates.injectBatchingStrategy(
    ReactDefaultBatchingStrategy
  );
}

这里的 ReactInjection.Updates 等于 ReactUpdates.injection 这个对象。而 inject 方法,就是在前文的 ReactDOM.js 中调用的方法ReactDefaultInjection.inject()。

上述各个文件整体的调用关系如下:

React 源码中的依赖注入方法

四、总结

本文介绍了依赖注入的基本概念,并结合 React 的源码讲解具体的使用场景。这样做的主要目的是解耦,可以根据实际的上下文传入不同的依赖对象,优雅的实现了代码的抽象与复用。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
在js中使用"with"语句中跨frame的变量引用问题
Mar 08 Javascript
33个优秀的 jQuery 图片展示插件分享
Mar 14 Javascript
JavaScript的事件绑定(方便不支持js的时候)
Oct 01 Javascript
js中通过父级进行查找定位元素
Jun 15 Javascript
jQuery实现简单的日期输入格式化控件
Mar 12 Javascript
JS+CSS实现下拉列表框美化效果(3款)
Aug 15 Javascript
浅析BootStrap Treeview的简单使用
Oct 12 Javascript
bootstrap flask登录页面编写实例
Nov 01 Javascript
详解AngularJS1.6版本中ui-router路由中/#!/的解决方法
May 22 Javascript
页面间固定参数,通过cookie传值的实现方法
May 31 Javascript
vue生命周期和react生命周期对比【推荐】
Sep 19 Javascript
angular2 组件之间通过service互相传递的实例
Sep 30 Javascript
监听angularJs列表数据是否渲染完毕的方法示例
Nov 07 #Javascript
详解react native页面间传递数据的几种方式
Nov 07 #Javascript
微信小程序使用npm支持踩坑
Nov 07 #Javascript
Angular Material Icon使用详解
Nov 07 #Javascript
详解Webpack loader 之 file-loader
Nov 07 #Javascript
JS复杂判断的更优雅写法代码详解
Nov 07 #Javascript
javascript动态创建对象的属性详解
Nov 07 #Javascript
You might like
PHP5 安装方法
2007/01/15 PHP
php ss7.5的数据调用 (笔记)
2010/03/08 PHP
Smarty日期时间操作方法示例
2016/11/15 PHP
PHP PDO操作MySQL基础教程
2017/06/05 PHP
php版本CKEditor 4和CKFinder安装及配置方法图文教程
2019/06/05 PHP
FormValid0.5版本发布,带ajax自定义验证例子
2007/08/17 Javascript
Prototype ObjectRange对象学习
2009/07/19 Javascript
调用innerHTML之后onclick失效问题的解决方法
2014/01/28 Javascript
5个可以帮你理解JavaScript核心闭包和作用域的小例子
2014/10/08 Javascript
jQuery插件开发的五种形态小结
2015/03/04 Javascript
iPhone手机上搭建nodejs服务器步骤方法
2015/07/06 NodeJs
js控制多图左右滚动切换效果代码分享
2015/08/26 Javascript
关于JavaScript中事件绑定的方法总结
2016/10/26 Javascript
值得学习的bootstrap fileinput文件上传工具
2016/11/08 Javascript
网络传输协议(http协议)
2016/11/18 Javascript
基于React实现表单数据的添加和删除详解
2017/03/14 Javascript
React 子组件向父组件传值的方法
2017/07/24 Javascript
JavaScript继承的特性与实践应用深入详解
2018/12/30 Javascript
JS散列表碰撞处理、开链法、HashTable散列示例
2019/02/08 Javascript
vue中使用v-model完成组件间的通信
2019/08/22 Javascript
node 文件上传接口的转发的实现
2019/09/23 Javascript
antd-DatePicker组件获取时间值,及相关设置方式
2020/10/27 Javascript
[01:00:13]完美世界DOTA2联赛 LBZS vs Forest 第一场 11.07
2020/11/09 DOTA
[39:19]完美世界DOTA2联赛PWL S2 SZ vs LBZS 第二场 11.26
2020/11/30 DOTA
python 中文乱码问题深入分析
2011/03/13 Python
Python使用MD5加密字符串示例
2014/08/22 Python
pymongo实现多结果进行多列排序的方法
2015/05/16 Python
Python selenium 三种等待方式详解(必会)
2016/09/15 Python
完美解决Python matplotlib绘图时汉字显示不正常的问题
2019/01/29 Python
python 含子图的gif生成时内存溢出的方法
2019/07/07 Python
python 的 openpyxl模块 读取 Excel文件的方法
2019/09/09 Python
部署Django到阿里云服务器教程示例
2020/06/03 Python
一款利用html5和css3动画排列人物头像的实例演示
2014/12/05 HTML / CSS
大学生毕业自我鉴定
2013/11/06 职场文书
电钳专业个人求职信
2014/01/04 职场文书
MySQL的join buffer原理
2021/04/29 MySQL