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树形控件脚本代码
Jul 24 Javascript
基于jquery的bankInput银行卡账号格式化
Aug 22 Javascript
zepto.js中tap事件阻止冒泡的实现方法
Feb 12 Javascript
js同源策略详解
May 21 Javascript
关于JavaScript的变量的数据类型的判断方法
Aug 14 Javascript
浅谈JavaScript 数据属性和访问器属性
Sep 01 Javascript
原生js验证简洁注册登录页面
Dec 17 Javascript
jQuery插件FusionCharts绘制的3D环饼图效果示例【附demo源码】
Apr 02 jQuery
基于JS脚本语言的基础语法详解
Jul 22 Javascript
vue实现的上传图片到数据库并显示到页面功能示例
Mar 17 Javascript
Vue 页面权限控制和登陆验证功能的实例代码
Jun 20 Javascript
Vue 自定义标签的src属性不能使用相对路径的解决
Sep 17 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
php中获取指定IP的物理地址的代码(正则表达式)
2011/06/23 PHP
php 无法加载mysql的module的时候的配置的解决方案引发的思考
2012/01/27 PHP
基于PHP实现用户注册登录功能
2016/10/14 PHP
PHP PDOStatement::execute讲解
2019/01/31 PHP
web页面数据展示新想法(json)
2010/06/08 Javascript
属于你的jQuery提示框(Tip)插件
2016/01/20 Javascript
Bootstrap每天必学之工具提示(Tooltip)插件
2016/04/26 Javascript
javascript获取网页各种高宽及位置的方法总结
2016/07/27 Javascript
浅谈JavaScript的自动垃圾收集机制
2016/12/15 Javascript
简单的网页广告特效实例
2017/08/19 Javascript
让bootstrap的carousel支持滑动滚屏的实现代码
2017/11/27 Javascript
浅谈基于Vue.js的移动组件库cube-ui
2017/12/20 Javascript
浅谈React的最大亮点之虚拟DOM
2018/05/29 Javascript
Taro集成Redux快速上手的方法示例
2018/06/21 Javascript
webpack css加载和图片加载的方法示例
2018/09/11 Javascript
Vue 重置组件到初始状态的方法示例
2018/10/10 Javascript
微信小程序websocket聊天室的实现示例代码
2019/02/12 Javascript
mpvue开发音频类小程序踩坑和建议详解
2019/03/12 Javascript
jQuery实现文本显示一段时间后隐藏的方法分析
2019/06/20 jQuery
微信小程序把百度地图坐标转换成腾讯地图坐标过程详解
2019/07/10 Javascript
[05:06]TI4西雅图DOTA2前线报道 海涛密探LGD训练
2014/07/09 DOTA
基于pandas将类别属性转化为数值属性的方法
2018/07/25 Python
PyQt5创建一个新窗口的实例
2019/06/20 Python
python3.x提取中文的正则表达式示例代码
2019/07/23 Python
TensorFlow打印输出tensor的值
2020/04/19 Python
基于python实现复制文件并重命名
2020/09/16 Python
网站性能延迟加载图像的五种技巧(小结)
2020/08/13 HTML / CSS
THE OUTNET美国官网:国际设计师品牌折扣网站
2017/03/07 全球购物
马来西亚网上美容店:Hermo.my
2017/11/25 全球购物
有针对性的求职自荐信
2013/11/14 职场文书
大学学习计划书范文
2014/05/02 职场文书
公司董事长岗位职责
2014/06/08 职场文书
精神文明建设标语
2014/06/16 职场文书
医院深入开展党的群众路线教育实践活动实施方案
2014/08/27 职场文书
2014年护士个人工作总结
2014/11/11 职场文书
中秋节寄语2015
2015/03/24 职场文书