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 AJAX返回的JSON结果集实现代码
Dec 10 Javascript
基于JQuery 选择器使用说明介绍
Apr 18 Javascript
分享20个提升网站界面体验的jQuery插件
Dec 15 Javascript
js实现文本框选中的方法
May 26 Javascript
node.js require() 源码解读
Dec 13 Javascript
解析JavaScript面向对象概念中的Object类型与作用域
May 10 Javascript
纯前端JavaScript实现Excel IO案例分享
Aug 26 Javascript
谈谈target=_new和_blank的不同之处
Oct 25 Javascript
详解vue项目首页加载速度优化
Oct 18 Javascript
Vue2.0+ElementUI实现表格翻页的实例
Oct 23 Javascript
JavaScript设计模式之单例模式简单实例教程
Jul 02 Javascript
微信小程序开发注意指南和优化实践(小结)
Jun 21 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
jq的get传参数在utf-8中乱码问题的解决php版
2008/07/23 PHP
用php或asp创建网页桌面快捷方式的代码
2010/03/23 PHP
php实现最简单的MVC框架实例教程
2014/09/08 PHP
yii2高级应用之自定义组件实现全局使用图片上传功能的方法
2016/10/08 PHP
关于 Laravel Redis 多个进程同时取队列问题详解
2017/12/25 PHP
PHP+MariaDB数据库操作基本技巧备忘总结
2018/05/21 PHP
jquery validator 插件增加日期比较方法
2010/02/21 Javascript
基于Jquery插件开发之图片放大镜效果(仿淘宝)
2011/11/19 Javascript
js面向对象 多种创建对象方法小结
2012/05/21 Javascript
jquery的ajax简单结构示例代码
2014/02/17 Javascript
node.js [superAgent] 请求使用示例
2015/03/13 Javascript
jquery中实现时间戳与日期相互转换
2016/04/12 Javascript
JavaScript实现页面跳转的方式汇总
2016/05/16 Javascript
浅谈jQuery双事件多重加载的问题
2016/10/05 Javascript
jQuery实现的checkbox级联选择下拉菜单效果示例
2016/12/26 Javascript
Angular路由简单学习
2016/12/26 Javascript
详解vue2.6插槽更新v-slot用法总结
2019/03/09 Javascript
JS通过识别id、value值对checkbox设置选中状态
2020/02/19 Javascript
vue 获取元素额外生成的data-v-xxx操作
2020/09/09 Javascript
[09:59]DOTA2-DPC中国联赛2月7日Recap集锦
2021/03/11 DOTA
使用python搭建Django应用程序步骤及版本冲突问题解决
2013/11/19 Python
Python写的创建文件夹自定义函数mkdir()
2014/08/25 Python
Windows下Eclipse+PyDev配置Python+PyQt4开发环境
2016/05/17 Python
Python的Flask框架中使用Flask-Migrate扩展迁移数据库的教程
2016/06/14 Python
一份python入门应该看的学习资料
2018/04/11 Python
对numpy中array和asarray的区别详解
2018/04/17 Python
python实现ID3决策树算法
2018/08/29 Python
对python中的argv和argc使用详解
2018/12/15 Python
Python学习笔记之Django创建第一个数据库模型的方法
2019/08/07 Python
Python flask框架如何显示图像到web页面
2020/06/03 Python
Python是如何进行类型转换的
2013/06/09 面试题
新员工培训个人的自我评价
2013/10/09 职场文书
毕业自荐信
2013/12/16 职场文书
数控专业自荐书范文
2014/03/16 职场文书
保证书格式范文
2014/04/28 职场文书
药店收银员岗位职责
2015/04/07 职场文书