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 相关文章推荐
javascript 控制 html元素 显示/隐藏实现代码
Sep 01 Javascript
JQuery优缺点分析说明
Apr 10 Javascript
ajax异步刷新实现更新数据库
Dec 03 Javascript
js类式继承的具体实现方法
Dec 31 Javascript
JQuery radio(单选按钮)操作方法汇总
Apr 15 Javascript
jQuery实现内容定时切换效果完整实例
Apr 06 Javascript
js与applet相互调用的方法
Jun 22 Javascript
JavaScript实现清空(重置)文件类型INPUT元素值的方法
Nov 17 Javascript
canvas 画布在主流浏览器中的尺寸限制详细介绍
Dec 15 Javascript
微信小程序 图片上传实例详解
May 05 Javascript
详解webpack分包及异步加载套路
Jun 29 Javascript
一步步教你利用Docker设置Node.js
Nov 20 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
phpmyadmin3 安装配置图解教程
2012/03/29 PHP
PHP 杂谈《重构-改善既有代码的设计》之四 简化条件表达式
2012/04/09 PHP
PHP获取浏览器信息类和客户端地理位置的2个方法
2014/04/24 PHP
浅谈php扩展imagick
2014/06/02 PHP
PHP对称加密算法(DES/AES)类的实现代码
2017/11/14 PHP
代码生成器 document.write()
2007/04/15 Javascript
javascript 动态添加事件代码
2008/11/30 Javascript
javascript 面向对象全新理练之继承与多态
2009/12/03 Javascript
JavaScript 判断指定字符串是否为有效数字
2010/05/11 Javascript
JS中闭包的经典用法小结(2则示例)
2016/12/28 Javascript
JavaScript使用原型和原型链实现对象继承的方法详解
2017/04/05 Javascript
Node.js+Express+MySql实现用户登录注册功能
2017/07/10 Javascript
OkHttp踩坑随笔为何 response.body().string() 只能调用一次
2018/01/08 Javascript
监控微信小程序中的慢HTTP请求过程详解
2019/07/05 Javascript
vue实现滑动切换效果(仅在手机模式下可用)
2020/06/29 Javascript
Egg Vue SSR 服务端渲染数据请求与asyncData
2019/11/24 Javascript
基于vue 动态菜单 刷新空白问题的解决
2020/08/06 Javascript
vue-cli单页面预渲染seo-prerender-spa-plugin操作
2020/08/10 Javascript
vue pages 多入口项目 + chainWebpack 全局引用缩写说明
2020/09/21 Javascript
10款最好的Web开发的 Python 框架
2015/03/18 Python
DataFrame中去除指定列为空的行方法
2018/04/08 Python
Python实现统计给定列表中指定数字出现次数的方法
2018/04/11 Python
python3下使用cv2.imwrite存储带有中文路径图片的方法
2018/05/10 Python
css3 给页面加个半圆形导航条主要利用旋转和倾斜样式
2014/02/10 HTML / CSS
英国最好的温室之家:Greenhouses Direct
2019/07/13 全球购物
Weblogc domain问题
2014/01/27 面试题
财务人员个人自荐信范文
2013/09/26 职场文书
小学教师事迹材料
2014/01/13 职场文书
面试后的感谢信范文
2014/02/01 职场文书
党员学习中共十八大思想报告
2014/09/12 职场文书
医务人员医德考评自我评价
2015/03/03 职场文书
对领导班子的意见和建议
2015/06/08 职场文书
保护地球的宣传语
2015/07/13 职场文书
MySQL学习总结-基础架构概述
2021/04/05 MySQL
教你快速构建一个基于nginx的web集群项目
2021/11/27 Servers
Python安装及建立虚拟环境的完整步骤
2022/06/25 Servers