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 MD4
Dec 20 Javascript
javascript采用数组实现tab菜单切换效果
Dec 12 Javascript
js jquery获取随机生成id的服务器控件的三种方法
Jul 11 Javascript
页面右下角弹出提示框示例代码js版
Aug 02 Javascript
JS获取月的最后一天与JS得到一个月份最大天数的实例代码
Dec 16 Javascript
jQuery旋转木马式幻灯片轮播特效
Dec 04 Javascript
由浅入深剖析Angular表单验证
Jul 14 Javascript
JS前端笔试题分析
Dec 19 Javascript
jQuery实现的仿百度,仿谷歌搜索下拉框效果示例
Dec 30 Javascript
jQuery ajax的功能实现方法详解
Jan 06 Javascript
详解elementui之el-image-viewer(图片查看器)
Aug 30 Javascript
原生JS实现天气预报
Jun 16 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
与空气斗智斗勇的经典《Overlord》,传说中的“无稽之谈”
2020/04/09 日漫
php cli配置文件问题分析
2015/10/15 PHP
PHP中模拟链表和链表的基本操作示例
2016/02/27 PHP
jQuery EasyUI API 中文文档 - Calendar日历使用
2011/10/19 Javascript
JS获取鼠标坐标的实例方法
2013/07/18 Javascript
JavaScript模拟深蓝vs卡斯帕罗夫的国际象棋对局示例
2015/04/22 Javascript
使用Sticky组件实现带sticky效果的tab导航和滚动导航的方法
2016/03/22 Javascript
微信小程序 表单Form实例详解(附源码)
2016/12/22 Javascript
纯原生js实现table表格的增删
2017/01/05 Javascript
JS实现点击拉拽轮播图pc端移动端适配
2018/09/05 Javascript
详解javascript设计模式三:代理模式
2019/03/25 Javascript
Jquery让form表单异步提交代码实现
2019/11/14 jQuery
Vue登录拦截 登录后继续跳转指定页面的操作
2020/08/04 Javascript
关于javascript中的promise的用法和注意事项(推荐)
2021/01/15 Javascript
[06:11]2014DOTA2国际邀请赛 专访团结一心的VG战队
2014/07/21 DOTA
一个简单的python程序实例(通讯录)
2013/11/29 Python
Python微信企业号开发之回调模式接收微信端客户端发送消息及被动返回消息示例
2017/08/21 Python
详解Python3的TFTP文件传输
2018/06/26 Python
对python中的装包与解包实例详解
2019/08/24 Python
Matplotlib绘制雷达图和三维图的示例代码
2020/01/07 Python
Tensorflow 模型转换 .pb convert to .lite实例
2020/02/12 Python
基于K.image_data_format() == 'channels_first' 的理解
2020/06/29 Python
基于python实现生成指定大小txt文档
2020/07/20 Python
Python pip install之SSL异常处理操作
2020/09/03 Python
详解解决jupyter不能使用pytorch的问题
2021/02/18 Python
Kipling凯浦林美国官网:世界著名时尚休闲包袋品牌
2016/08/24 全球购物
美国眼镜网站:EyeBuyDirect
2017/04/13 全球购物
教师求职信范文分享
2013/12/27 职场文书
寄语是什么意思
2014/04/10 职场文书
宣传普通话标语
2014/06/27 职场文书
小学校园文化建设汇报材料
2014/08/19 职场文书
党的群众路线教育实践活动查摆问题自查报告
2014/10/10 职场文书
2014年政协工作总结
2014/12/09 职场文书
应急管理工作总结2015
2015/05/04 职场文书
Angular性能优化之第三方组件和懒加载技术
2021/05/10 Javascript
SQL Server中使用判断语句(IF ELSE/CASE WHEN )案例
2021/07/07 SQL Server