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 的源码讲解具体的使用场景。这样做的主要目的是解耦,可以根据实际的上下文传入不同的依赖对象,优雅的实现了代码的抽象与复用。
文章同步发布: https://www.geek-share.com/detail/2752558290.html
React 源码中的依赖注入方法的更多相关文章
- AngularJS源码分析之依赖注入$injector
开篇 随着javaEE的spring框架的兴起,依赖注入(IoC)的概念彻底深入人心,它彻底改变了我们的编码模式和思维.在IoC之前,我们在程序中需要创建一个对象很简单也很直接,就是在代码中new O ...
- monkey源码分析之事件注入方法变化
在上一篇文章<Monkey源码分析之事件注入>中,我们看到了monkey在注入事件的时候用到了<Monkey源码分析番外篇之Android注入事件的三种方法比较>中的第一种方法 ...
- angular源码阅读,依赖注入的原理:injector,provider,module之间的关系。
最开始使用angular的时候,总是觉得它的依赖注入方式非常神奇. 如果你跳槽的时候对新公司说,我曾经使用过angular,那他们肯定会问你angular的依赖注入原理是什么? 这篇博客其实是angu ...
- [Abp vNext 源码分析] - 3. 依赖注入与拦截器
一.简要说明 ABP vNext 框架在使用依赖注入服务的时候,是直接使用的微软提供的 Microsoft.Extensions.DependencyInjection 包.这里与原来的 ABP 框架 ...
- 【Spring源码解析】—— 依赖注入结合SpringMVC Demo-xml配置理解
在IOC容器初始化的梳理之后,对依赖注入做一个总结,就是bean实例化的过程,bean的定义有两种方式,一种是xml文件配置,一种是注解,这里是对xml配置文件的依赖注入的介绍,后续对bean与该部分 ...
- 小白都能看懂的 Spring 源码揭秘之依赖注入(DI)源码分析
目录 前言 依赖注入的入口方法 依赖注入流程分析 AbstractBeanFactory#getBean AbstractBeanFactory#doGetBean AbstractAutowireC ...
- ABP框架源码中的Linq扩展方法
文件目录:aspnetboilerplate-dev\aspnetboilerplate-dev\src\Abp\Collections\Extensions\EnumerableExtensions ...
- 【神经网络与深度学习】Caffe源码中各种依赖库的作用及简单使用
1. Boost库:它是一个可移植.跨平台,提供源代码的C++库,作为标准库的后备. 在Caffe中用到的Boost头文件包括: (1).shared_ptr.hpp:智能指针,使用它可以不 ...
- netty学习--netty源码中的部分util方法
io.netty.buffer.AbstractByteBuf#calculateNewCapacity 申请内存空间 private int calculateNewCapacity(int mi ...
随机推荐
- centos7和centos6区别
CentOS 7 vs CentOS 6的不同 (1)桌面系统[CentOS6] GNOME 2.x[CentOS7] GNOME 3.x(GNOME Shell) (2)文件系统[CentOS6 ...
- java代码修改了之后运行仍然是原程序
有的时候java代码改了之后但是运行的程序却没有发生改动,这是什么情况呢?可能懂得的人都觉得十分简单,但对于我这样的小白来说确实很费力.java代码更改后需要编译生成.class文件,说的直白点,这个 ...
- [EffectiveC++]item35:考虑virtual函数以外的其他选择
本质上是说了: Template Pattern & Strategy Pattern 详细见<C++设计模式 23种设计模式.pdf 55页> 宁可要组合 不要继承. ——— ...
- Codeforces Round #433 (Div. 2)【A、B、C、D题】
题目链接:Codeforces Round #433 (Div. 2) codeforces 854 A. Fraction[水] 题意:已知分子与分母的和,求分子小于分母的 最大的最简分数. #in ...
- HBase的rowkey排序和scan输出顺序
本文目的:搞清楚HBase里面行与行之间的排序排序规则,如何正序和反序输出扫描结果. 明确: HBase里面同一列的元素按照rowkey进行排序,排序规则是rowkey的ASCII码排序,小的在前大的 ...
- PHP语言开发微信公众平台(订阅号)之curl命令(补充)
在之前的一篇随笔中,博主在调用curl命令上传文件时会经常出现上传方法过时的情况.如下图所示: 所以,我们只需要把上传方法换成创建CURLFile 类即可.如下所示 $ch = curl_init() ...
- Leetcode225 用栈实现队列
大众思路: 用两个栈实现,记为s1,s2 1.元素入栈时,加入s1 2.元素出栈时,对s2进行判断,如果s2为空,则将全部s1元素弹出并压入到s2,然后从s2栈顶弹出一个元素:如果s2不为空,则直接从 ...
- RabbitMQ之五种消息模型
首先什么是MQ MQ全称是Message Queue,即消息对列!消息队列是典型的:生产者.消费者模型.生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息.因为消息的生产和消费都是异步的,而 ...
- git上传下载代码操作
提交代码实质上都要走这样的操作 " 本地代码 --> 本地服务器" "本地服务器 --> 远程服务器" 其实小伙伴就记住两个词就好了. Commi ...
- webAPI请求消息过滤器
每当制作一个WebAPI,就必然会收到外部很多调用这个API的请求,有时候,我们希望,能从这些外部来的请求中,按照一定条件筛选过滤一下,只将那些我们觉得合法的,有必要回应的请求放进来,一方面挡住那些非 ...