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 限制输入脚本大全
Nov 03 Javascript
php上传图片并给图片打上透明水印的代码
Jun 07 Javascript
div浮层,滚动条移动,位置保持不变的4种方法汇总
Dec 11 Javascript
javascript中数组的concat()方法使用介绍
Dec 18 Javascript
javascript解决IE6下hover问题的方法
Jul 28 Javascript
javascript实现五星评价代码(源码下载)
Aug 11 Javascript
JavaScript提升性能的常用技巧总结【经典】
Jun 20 Javascript
Javascript+CSS3实现进度条效果
Oct 28 Javascript
php简单数据库操作类的封装
Jun 08 Javascript
JavaScript实现单例模式实例分享
Dec 22 Javascript
JS实现简单的文字无缝上下滚动功能示例
Jun 22 Javascript
Vue是怎么渲染template内的标签内容的
Jun 05 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在获取指定目录下的目录,在获取的目录下面再创建文件,多平台
2011/08/03 PHP
php中rename函数用法分析
2014/11/15 PHP
php相对当前文件include其它文件的方法
2015/03/13 PHP
PHP调用微博接口实现微博登录的方法示例
2018/09/22 PHP
PHP使用Redis实现Session共享的实现示例
2019/05/12 PHP
jquery实现的代替传统checkbox样式插件
2015/06/19 Javascript
14款经典网页图片和文字特效的jQuery插件-前端开发必备
2015/08/25 Javascript
js实现的页面矩阵图形变换特效
2016/01/26 Javascript
jQuery实现可展开折叠的导航效果示例
2016/09/12 Javascript
js 打开新页面在屏幕中间的实现方法
2016/11/02 Javascript
jQuery实现checkbox列表的全选、反选功能
2016/11/24 Javascript
Angular 2父子组件数据传递之@Input和@Output详解(下)
2017/07/05 Javascript
在React中如何优雅的处理事件响应详解
2017/07/24 Javascript
jQuery实现点击DIV同时点击CheckBox,并为DIV上背景色的实例
2017/12/18 jQuery
vue项目动态设置页面title及是否缓存页面的问题
2018/11/08 Javascript
JS实现获取数组中最大值或最小值功能示例
2019/03/02 Javascript
Vue.js路由实现选项卡简单实例
2019/07/24 Javascript
nodejs使用node-xlsx生成excel的方法示例
2019/08/22 NodeJs
JQuery事件冒泡和默认行为代码实例
2020/05/13 jQuery
学习python (1)
2006/10/31 Python
Python装饰器decorator用法实例
2014/11/10 Python
TF-IDF与余弦相似性的应用(一) 自动提取关键词
2017/12/21 Python
python实现ip代理池功能示例
2019/07/05 Python
Python爬取破解无线网络wifi密码过程解析
2019/09/17 Python
pandas factorize实现将字符串特征转化为数字特征
2019/12/19 Python
在keras中实现查看其训练loss值
2020/06/16 Python
如何将json数据转换为python数据
2020/09/04 Python
Merrell迈乐澳大利亚网站:购买户外登山鞋
2017/05/28 全球购物
戴尔马来西亚官网:Dell Malaysia
2020/05/02 全球购物
DBA数据库管理员JAVA程序员架构师必看
2016/02/07 面试题
仪器仪表检测毕业生自荐信
2013/10/31 职场文书
国际贸易个人求职信范文
2014/01/04 职场文书
小学数学教师研修感悟
2015/11/18 职场文书
【超详细】八大排序算法的各项比较以及各自特点
2021/03/31 Python
python 中的@运算符使用
2021/05/26 Python
面试中canvas绘制图片模糊图片问题处理
2022/03/13 Javascript