一、前言

依赖注入(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 源码中的依赖注入方法的更多相关文章

  1. AngularJS源码分析之依赖注入$injector

    开篇 随着javaEE的spring框架的兴起,依赖注入(IoC)的概念彻底深入人心,它彻底改变了我们的编码模式和思维.在IoC之前,我们在程序中需要创建一个对象很简单也很直接,就是在代码中new O ...

  2. monkey源码分析之事件注入方法变化

    在上一篇文章<Monkey源码分析之事件注入>中,我们看到了monkey在注入事件的时候用到了<Monkey源码分析番外篇之Android注入事件的三种方法比较>中的第一种方法 ...

  3. angular源码阅读,依赖注入的原理:injector,provider,module之间的关系。

    最开始使用angular的时候,总是觉得它的依赖注入方式非常神奇. 如果你跳槽的时候对新公司说,我曾经使用过angular,那他们肯定会问你angular的依赖注入原理是什么? 这篇博客其实是angu ...

  4. [Abp vNext 源码分析] - 3. 依赖注入与拦截器

    一.简要说明 ABP vNext 框架在使用依赖注入服务的时候,是直接使用的微软提供的 Microsoft.Extensions.DependencyInjection 包.这里与原来的 ABP 框架 ...

  5. 【Spring源码解析】—— 依赖注入结合SpringMVC Demo-xml配置理解

    在IOC容器初始化的梳理之后,对依赖注入做一个总结,就是bean实例化的过程,bean的定义有两种方式,一种是xml文件配置,一种是注解,这里是对xml配置文件的依赖注入的介绍,后续对bean与该部分 ...

  6. 小白都能看懂的 Spring 源码揭秘之依赖注入(DI)源码分析

    目录 前言 依赖注入的入口方法 依赖注入流程分析 AbstractBeanFactory#getBean AbstractBeanFactory#doGetBean AbstractAutowireC ...

  7. ABP框架源码中的Linq扩展方法

    文件目录:aspnetboilerplate-dev\aspnetboilerplate-dev\src\Abp\Collections\Extensions\EnumerableExtensions ...

  8. 【神经网络与深度学习】Caffe源码中各种依赖库的作用及简单使用

    1.      Boost库:它是一个可移植.跨平台,提供源代码的C++库,作为标准库的后备. 在Caffe中用到的Boost头文件包括: (1).shared_ptr.hpp:智能指针,使用它可以不 ...

  9. netty学习--netty源码中的部分util方法

    io.netty.buffer.AbstractByteBuf#calculateNewCapacity  申请内存空间 private int calculateNewCapacity(int mi ...

随机推荐

  1. 爬虫入门之Scrapy框架基础框架结构及腾讯爬取(十)

    Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取的数据. 如果安装了 IPyth ...

  2. 【Leetcode】【Medium】Gray Code

    The gray code is a binary numeral system where two successive values differ in only one bit. Given a ...

  3. FQDN说明

    以下摘自百度百科: FQDN:(Fully Qualified Domain Name)完全合格域名/全称域名,是指主机名加上全路径,全路径中列出了序列中所有域成员.全域名可以从逻辑上准确地表示出主机 ...

  4. selenium层级定位及鼠标键盘操作

    #code:utf-8 from selenium import webdriver from selenium.webdriver.common.action_chains import Actio ...

  5. 为什么说 Java 程序员必须掌握 Spring Boot ?

    原作者https://www.cnblogs.com/ityouknow/p/9175980.html Spring Boot 2.0 的推出又激起了一阵学习 Spring Boot 热,就单从我个人 ...

  6. C#图解教程读书笔记(第7章 类和继承)

    1.所有的类都继承自object 2.如何隐藏基类的成员 要隐藏一个继承的数据成员,需要声明一个新的相同类型的成员,并使用相同的名称. 通过在派生类中声明新的带有相同签名的函数成员,可以隐藏或掩盖继承 ...

  7. aop的概念以及 cglib-nodep-2.1_3.jar第三方jia包动态代理使用

    引入 cglib-nodep-2.1_3.ja包 cglib产生的代理类是目标类的子类 定义接口,让切面都继承它,方便加入到动态代理方法 的那个类中使用 在SalaryInterceptor类中使用  ...

  8. CentOS下go 安装

     go 语言源码安装依赖 ,gcc ,make glibc库,等,上述工具安装省略,另外,其源代码更新采用的是mercurial 工具,安装前先安装mercureal :   1.mercurial安 ...

  9. BZOJ3245:最快路线(最短路)

    Description 精明的小R每每开车出行总是喜欢走最快路线,而不是最短路线.很明显,每条道路的限速是小R需要考虑的关键问题.不过有一些限速标志丢失了,于是小R将不知道能开多快.不过有一个合理的方 ...

  10. Codeforces Round #527 (Div. 3) D2. Great Vova Wall (Version 2) 【思维】

    传送门:http://codeforces.com/contest/1092/problem/D2 D2. Great Vova Wall (Version 2) time limit per tes ...