React 源码中的依赖注入方法
一、前言
依赖注入(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 的源码讲解具体的使用场景。这样做的主要目的是解耦,可以根据实际的上下文传入不同的依赖对象,优雅的实现了代码的抽象与复用。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 保健警惕 7大坏习惯最伤宝宝牙齿
下一篇: webstorm+vue初始化项目的方法