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 相关文章推荐
论坛特效代码收集(落伍转发-不错)
Dec 02 Javascript
用 JavaScript 迁移目录
Dec 18 Javascript
jquery tab插件精简版分享
Sep 10 Javascript
关于include标签导致js路径找不到的问题分析及解决
Jul 09 Javascript
JavaScript删除数组元素的方法
Mar 20 Javascript
Laravel中常见的错误与解决方法小结
Aug 30 Javascript
文件上传的几个示例分享【推荐】
Dec 16 Javascript
echarts学习笔记之图表自适应问题详解
Nov 22 Javascript
vue2实现搜索结果中的搜索关键字高亮的代码
Aug 29 Javascript
微信小程序收货地址API兼容低版本解决方法
May 18 Javascript
laydate只显示时分 不显示秒的功能实现方法
Sep 28 Javascript
ztree+ajax实现文件树下载功能
May 18 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实现把数组按指定的个数分隔
2014/02/17 PHP
用window.location.href实现刷新另个框架页面
2007/03/07 Javascript
jQuery 添加/移除CSS类实现代码
2010/02/11 Javascript
关于全局变量和局部变量的那些事
2013/01/11 Javascript
JS性能优化笔记搜索整理
2013/08/21 Javascript
js实现右下角提示框的方法
2015/02/03 Javascript
jQuery实现360°全景拖动展示
2015/03/18 Javascript
javascript实现链接单选效果的方法
2015/05/13 Javascript
jquery实现鼠标点击后展开列表内容的导航栏效果
2015/09/14 Javascript
JavaScript实现的浮动层框架用法实例分析
2015/10/10 Javascript
Jquery全屏相册插件zoomvisualizer具有调节放大与缩小功能
2015/11/02 Javascript
JavaScript表单验证实例之验证表单项是否为空
2016/01/10 Javascript
一览画面点击复选框后获取多个id值的方法
2016/05/30 Javascript
jQuery插件简单学习实例教程
2016/07/01 Javascript
jQuery 生成svg矢量二维码
2016/08/09 Javascript
深入理解AngularJS中的ng-bind-html指令和$sce服务
2016/09/08 Javascript
Bootstrap CSS使用方法
2016/12/23 Javascript
详解用webpack2搭建angular2的项目
2017/06/22 Javascript
vuex actions传递多参数的处理方法
2018/09/18 Javascript
Vue.js实现可编辑的表格
2019/12/11 Javascript
Vue 解决在element中使用$notify在提示信息中换行问题
2020/11/11 Javascript
解决pyqt中ui编译成窗体.py中文乱码的问题
2016/12/23 Python
使用Python操作excel文件的实例代码
2017/10/15 Python
Python编写一个优美的下载器
2018/04/15 Python
python中map的基本用法示例
2018/09/10 Python
Python 中判断列表是否为空的方法
2019/11/24 Python
详解Python高阶函数
2020/08/15 Python
利用pipenv和pyenv管理多个相互独立的Python虚拟开发环境
2020/11/01 Python
python两种获取剪贴板内容的方法
2020/11/06 Python
Django用内置方法实现简单搜索功能的方法
2020/12/18 Python
公务员职业生涯规划书范文  
2014/01/19 职场文书
内勤主管岗位职责
2014/04/03 职场文书
六一儿童节演讲稿
2014/05/23 职场文书
golang elasticsearch Client的使用详解
2021/05/05 Golang
超详细教你怎么升级Mysql的版本
2021/05/19 MySQL
Python Pandas解析读写 CSV 文件
2022/04/11 Python