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之AJAX框架使用说明
Apr 24 Javascript
基于Jquery的开发个代阴影的对话框效果代码
Jul 28 Javascript
修复IE9&safari 的sort方法
Oct 21 Javascript
什么是 AngularJS?AngularJS简介
Dec 06 Javascript
javascript html5 canvas实现可拖动省份的中国地图
Mar 11 Javascript
Express之get,pos请求参数的获取
May 02 Javascript
vuejs手把手教你写一个完整的购物车实例代码
Jul 06 Javascript
基于JavaScript实现简单的音频播放功能
Jan 07 Javascript
vue.js响应式原理解析与实现
Jun 22 Javascript
jQuery选择器之基本过滤选择器用法实例分析
Feb 19 jQuery
javascript-hashchange事件和历史状态管理实例分析
Apr 18 Javascript
JS定时器如何实现提交成功提示功能
Jun 12 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
phpmyadmin 访问被拒绝的真实原因
2009/06/15 PHP
PHP foreach遍历多维数组实现方式
2016/11/16 PHP
JS 拼图游戏 面向对象,注释完整。
2009/06/18 Javascript
jQuery + Flex 通过拖拽方式动态改变图片的代码
2011/08/03 Javascript
javascript动态添加、修改、删除对象的属性与方法详解
2014/01/27 Javascript
jQuery选择器源码解读(五):tokenize的解析过程
2015/03/31 Javascript
JavaScript实现单击下拉框选择直接跳转页面的方法
2015/07/02 Javascript
jQuery中$this和$(this)的区别介绍(一看就懂)
2015/07/06 Javascript
JavaScript使用encodeURI()和decodeURI()获取字符串值的方法
2015/08/04 Javascript
详解iframe与frame的区别
2016/01/13 Javascript
js利用appendChild对标签进行排序的实现方法
2016/10/16 Javascript
利用Angularjs中模块ui-route管理状态的方法
2016/12/27 Javascript
bootstrap daterangepicker汉化以及扩展功能
2017/06/15 Javascript
详解JS获取HTML DOM元素的8种方法
2017/06/17 Javascript
利用Vue的v-for和v-bind实现列表颜色切换
2020/07/17 Javascript
js+canvas实现五子棋小游戏
2020/08/02 Javascript
浅谈vue中get请求解决传输数据是数组格式的问题
2020/08/03 Javascript
[02:02]2018DOTA2亚洲邀请赛Mineski赛前采访
2018/04/04 DOTA
[34:10]Secret vs VG 2019国际邀请赛淘汰赛 败者组 BO3 第二场 8.24
2019/09/10 DOTA
python实现的udp协议Server和Client代码实例
2014/06/04 Python
详解Python字符串对象的实现
2015/12/24 Python
Python的Twisted框架中使用Deferred对象来管理回调函数
2016/05/25 Python
python编程实现12306的一个小爬虫实例
2017/12/27 Python
一个月入门Python爬虫学习,轻松爬取大规模数据
2018/01/03 Python
python通过微信发送邮件实现电脑关机
2018/06/20 Python
Python数据分析matplotlib设置多个子图的间距方法
2018/08/03 Python
Python socket实现的简单通信功能示例
2018/08/21 Python
Python Django框架单元测试之文件上传测试示例
2019/05/17 Python
python中使用ctypes调用so传参设置遇到的问题及解决方法
2019/06/19 Python
澳大利亚体育和露营装备在线/实体零售商:Find Sports
2020/06/03 全球购物
老师给学生的表扬信
2014/01/17 职场文书
综合内勤岗位职责
2014/04/14 职场文书
娱乐节目策划方案
2014/06/10 职场文书
求职意向书
2014/07/29 职场文书
2014年应急管理工作总结
2014/11/26 职场文书
美丽人生观后感
2015/06/03 职场文书