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 相关文章推荐
Javascript的闭包
Dec 31 Javascript
Jquery replace 字符替换实现代码
Dec 02 Javascript
javascript 学习笔记(八)javascript对象
Apr 12 Javascript
jQuery瀑布流插件Wookmark使用实例
Apr 02 Javascript
JS实现点击按钮控制Div变宽、增高及调整背景色的方法
Aug 05 Javascript
html+js+highcharts绘制圆饼图表的简单实例
Aug 04 Javascript
巧用jQuery选择器提高写表单效率的方法
Aug 19 Javascript
JS控制FileUpload的上传文件类型实例代码
Oct 07 Javascript
vue中vee validate表单校验的几种基本使用
Jun 25 Javascript
JS实现Cookie读、写、删除操作工具类示例
Aug 28 Javascript
小程序api实现promise封装过程解析
Nov 21 Javascript
vue实现锚点定位功能
Jun 29 Vue.js
监听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
从零开始学YII2框架(二)通过 Composer 安装扩展插件
2014/08/20 PHP
php jsonp单引号转义
2014/11/23 PHP
支付宝接口开发集成支付环境小结
2015/03/17 PHP
twig模板常用语句实例小结
2016/02/04 PHP
PHP错误和异常处理功能模块示例
2016/11/12 PHP
php数据库操作model类(使用__call方法)
2016/11/16 PHP
Laravel 加载第三方类库的方法
2018/04/20 PHP
PHP执行普通shell命令流程解析
2020/08/24 PHP
javascript,jquery闭包概念分析
2010/06/19 Javascript
jQuery学习笔记 更改jQuery对象
2012/09/19 Javascript
JavaScript快速检测浏览器对CSS3特性的支持情况
2012/09/26 Javascript
jQuery不使用插件及swf实现无刷新文件上传
2014/12/08 Javascript
用模版生成HTML的的框架jquery.tmpl使用详解
2015/01/07 Javascript
详解AngularJS中的表达式使用
2015/06/16 Javascript
jQuery-1.9.1源码分析系列(十)事件系统之事件包装
2015/11/20 Javascript
jquery实现tab键进行选择后enter键触发click行为
2017/03/29 jQuery
JS简单获取日期相差天数的方法
2017/04/24 Javascript
JavaScript创建对象方式总结【工厂模式、构造函数模式、原型模式等】
2018/12/19 Javascript
JavaScript 扩展运算符用法实例小结【基于ES6】
2019/06/17 Javascript
node.js如何根据URL返回指定的图片详解
2020/10/21 Javascript
解决ant Design Search无法输入内容的问题
2020/10/29 Javascript
[07:54]DOTA2 MV《我的动力鞋》 ImbaTV 出品
2014/11/21 DOTA
[02:08]2018年度CS GO枪械皮肤设计大赛优秀作者-完美盛典
2018/12/16 DOTA
python的urllib模块显示下载进度示例
2014/01/17 Python
Python中的startswith和endswith函数使用实例
2014/08/25 Python
Python之时间和日期使用小结
2019/02/14 Python
Python实现读取txt文件中的数据并绘制出图形操作示例
2019/02/26 Python
python操作redis数据库的三种方法
2020/09/10 Python
Django celery异步任务实现代码示例
2020/11/26 Python
Python 实现一个简单的web服务器
2021/01/03 Python
党课培训心得体会
2014/09/02 职场文书
法律意见书范本
2015/06/04 职场文书
退休欢送会主持词
2015/07/01 职场文书
2016党员干部廉洁自律心得体会
2016/01/13 职场文书
纪念建国70周年演讲稿
2019/07/19 职场文书
Python学习之包与模块详解
2022/03/19 Python