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 相关文章推荐
jQuery 第二课 操作包装集元素代码
Mar 14 Javascript
基于jquery的tab切换 js原理
Apr 01 Javascript
自写简单JS判断是否已经弹出页面
Oct 20 Javascript
JS实现的简洁二级导航菜单雏形效果
Oct 13 Javascript
js实现楼层效果的简单实例
Jul 15 Javascript
js点击任意区域弹出层消失实现代码
Dec 27 Javascript
微信小程序 详解下拉加载与上拉刷新实现方法
Jan 13 Javascript
vue服务端渲染的实例代码
Aug 28 Javascript
使用vue-infinite-scroll实现无限滚动效果
Jun 22 Javascript
浅谈vue项目打包优化策略
Sep 29 Javascript
如何用原生js写一个弹窗消息提醒插件
May 24 Javascript
layui使用form表单实现post请求页面跳转的方法
Sep 14 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 404错误页面实现代码
2009/06/22 PHP
thinkPHP分组后模板无法加载问题解决方法
2016/07/12 PHP
JavaScript判断两种格式的输入日期的正确性的代码
2007/03/25 Javascript
Dojo之路:如何利用Dojo实现Drag and Drop效果
2007/04/10 Javascript
基于jQuery的一个扩展form序列化到json对象
2010/12/09 Javascript
jQuery实现类似淘宝购物车全选状态示例
2013/06/26 Javascript
基于JavaScript 下namespace 功能的简单分析
2013/07/05 Javascript
js/html光标定位的实现代码
2013/09/23 Javascript
JavaScript实现自动生成网页元素功能(按钮、文本等)
2015/11/21 Javascript
node.js与C语言 实现遍历文件夹下最大的文件,并输出路径,大小
2017/01/20 Javascript
使用bootstrap-paginator.js 分页来进行ajax 异步分页请求示例
2017/03/09 Javascript
ES6新特性之类(Class)和继承(Extends)相关概念与用法分析
2017/05/24 Javascript
Bootstrap下拉菜单更改为悬停(hover)触发的方法
2017/05/24 Javascript
vue中mint-ui的使用方法
2018/04/04 Javascript
解决JS表单验证只有第一个IF起作用的问题
2018/12/04 Javascript
再也不怕 JavaScript 报错了,怎么看怎么处理都在这儿
2020/12/09 Javascript
[01:20]DOTA2 2017国际邀请赛冠军之路无止竞
2017/06/19 DOTA
[37:47]IG vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
[32:36]完美世界DOTA2联赛PWL S3 LBZS vs CPG 第二场 12.12
2020/12/16 DOTA
Python中获取网页状态码的两个方法
2014/11/03 Python
Python爬取三国演义的实现方法
2016/09/12 Python
Python探索之自定义实现线程池
2017/10/27 Python
python模块smtplib实现纯文本邮件发送功能
2018/05/22 Python
Python发送邮件功能示例【使用QQ邮箱】
2018/12/04 Python
django之静态文件 django 2.0 在网页中显示图片的例子
2019/07/28 Python
Python模块的制作方法实例分析
2019/12/21 Python
matplotlib jupyter notebook 图像可视化 plt show操作
2020/04/24 Python
Python configparser模块常用方法解析
2020/05/22 Python
浅谈keras中的keras.utils.to_categorical用法
2020/07/02 Python
如何用 Python 制作 GitHub 消息助手
2021/02/20 Python
分厂厂长岗位职责
2013/12/29 职场文书
应届毕业生简历自我评价
2014/01/31 职场文书
股权转让意向书
2014/04/01 职场文书
医院信息公开实施方案
2014/05/09 职场文书
导游词之河姆渡遗址博物馆
2019/10/10 职场文书
关于Nginx中虚拟主机的一些冷门知识小结
2022/03/03 Servers