• 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

  • 相关阅读:
    encode 与 decode
    pthon_flask小汇总
    jquery 动态添加标签而且指定样式
    设置Myeclipse中的代码格式化、及保存时自动格式化
    a href="javascript:void(0)" 是什么意思?与 a href="#" 加不加上有什么区别?
    String类 与StringBuffer类
    Java中的String类与StringBuffer类
    获取系统的当前时间
    switch 中可以使用字符串当判断条件
    关于接口的那些事
  • 原文地址:https://www.cnblogs.com/xxcn/p/9933254.html
Copyright © 2020-2023  润新知