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实现计算加载页面所用的时间
Apr 02 Javascript
javascript中怎么做对象的类型判断
Nov 11 Javascript
AJAX跨域请求json数据的实现方法
Nov 11 Javascript
js实现日期级联效果
Jan 23 Javascript
使用JS+plupload直接批量上传图片到又拍云
Dec 01 Javascript
JavaScript中的some()方法使用详解
Jun 09 Javascript
JavaScript类型系统之Object详解
Jan 07 Javascript
js计算时间差代码【包括计算,天,时,分,秒】
Apr 26 Javascript
JavaScript知识点总结(五)之Javascript中两个等于号(==)和三个等于号(===)的区别
May 31 Javascript
jQuery实现微信长按识别二维码功能
Aug 26 Javascript
JavaScript使用链式方法封装jQuery中CSS()方法示例
Apr 07 jQuery
angular框架实现全选与单选chekbox的自定义
Jul 06 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
递归列出所有文件和目录
2006/10/09 PHP
《PHP编程最快明白》第二讲 数字、浮点、布尔型、字符串和数组
2010/11/01 PHP
Session保存到数据库的php类分享
2011/10/24 PHP
深入php中var_dump方法的使用详解
2013/06/24 PHP
php实现12306火车票余票查询和价格查询(12306火车票查询)
2014/01/14 PHP
简单分析ucenter 会员同步登录通信原理
2014/08/25 PHP
yum命令安装php7和相关扩展
2016/07/04 PHP
yii2.0整合阿里云oss上传单个文件的示例
2017/09/19 PHP
Laravel使用原生sql语句并调用的方法
2019/10/09 PHP
php让json_encode不自动转义斜杠“/”的方法
2020/04/27 PHP
防止动态加载JavaScript引起的内存泄漏问题
2009/10/08 Javascript
jQuery实现模拟marquee标签效果
2015/07/14 Javascript
jQuery+JSON实现AJAX二级联动实例分析
2015/12/18 Javascript
微信小程序实现日历签到
2020/09/21 Javascript
[01:26]神话结束了,却也刚刚开始——DOTA2新英雄玛尔斯驾临战场
2019/03/10 DOTA
Python最基本的输入输出详解
2015/04/25 Python
Python中使用OpenCV库来进行简单的气象学遥感影像计算
2016/02/19 Python
python生成式的send()方法(详解)
2017/05/08 Python
Python使用正则表达式获取网页中所需要的信息
2018/01/29 Python
Python 读取图片文件为矩阵和保存矩阵为图片的方法
2018/04/27 Python
PyTorch使用cpu加载模型运算方式
2020/01/13 Python
Python cookie的保存与读取、SSL讲解
2020/02/17 Python
Python基于内置库pytesseract实现图片验证码识别功能
2020/02/24 Python
Tensorflow中的降维函数tf.reduce_*使用总结
2020/04/20 Python
Keras 加载已经训练好的模型进行预测操作
2020/06/17 Python
Python实现我的世界小游戏源代码
2021/03/02 Python
美国百年历史早餐食品供应商:Wolferman’s
2017/01/18 全球购物
泰国网上购物:Shopee泰国
2018/09/14 全球购物
什么是"引用"?申明和使用"引用"要注意哪些问题?
2016/03/03 面试题
就业推荐自我鉴定
2013/10/06 职场文书
房产委托公证书样本
2014/04/04 职场文书
全国优秀教师事迹材料
2014/08/26 职场文书
2014年食品安全工作总结
2014/12/04 职场文书
中学生运动会广播稿
2015/08/19 职场文书
PHP连接MSSQL数据库案例,PHPWAMP多个PHP版本连接SQL Server数据库
2021/04/16 PHP
python tkinter Entry控件的焦点移动操作
2021/05/22 Python