React Native 模块中的依赖注入

Posted

技术标签:

【中文标题】React Native 模块中的依赖注入【英文标题】:Dependency Injection in React Native modules 【发布时间】:2016-05-10 15:03:22 【问题描述】:

我们正在逐步将我的应用程序转换为 React Native。 而且我一直遇到 ios 上 React Native 中的依赖注入问题。

我的应用中有一些服务想在本机模块中使用。目前,它们是通过台风注入的,一切正常。

但是,React Native 本身会将任何本机模块初始化并维护为单例。这阻止了我让 Typhoon 初始化它们,因此我无法向它们注入依赖项。

可以做什么?自己创建 RCTBridge 是一种选择,但感觉很底层,还需要一开始就想办法把它注入到 UIView 中。

【问题讨论】:

【参考方案1】:

我不确定为什么您的问题没有得到更多的支持;我自己也在努力回答同样的问题,并认为我应该继续回答我的第一个 *** 问题!

在RCTBridge class 周围挖掘提供了答案。您需要做的是使用实现 RCTBridgeProtocol 的类的实例手动初始化 RCTBridge(重要的是方法“extraModulesForBridge”;如果您愿意,您甚至可以在视图控制器中实现此协议。

// Initialise a class that implements RCTBridgeDelegate
// Be warned, RCTBridge won't store a strong reference to your delegate.
// You should there store this delegate as a property of your initialising class, or implement the protocol in the View Controller itself. 
id<RCTBridgeDelegate> moduleInitialiser = [[classThatImplementsRCTBridgeDelegate alloc] init];

// Create a RCTBridge instance 
// (you may store this in a static context if you wish to use with other RCTViews you might initialise.  
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:moduleInitialiser launchOptions:nil];

// Initialise an RCTRootView
RCTRootView *rootView = [[RCTRootView alloc]
                     initWithBridge:bridge
                         moduleName:kModuleName
                  initialProperties:nil];

// Note that your class that implements RCTBridgeDelegate SHOULD implement the following methods and it might look something like this.

// This will return the location of our Bundle
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge

    return [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];


// Importantly, this is the method we need to implement to answer this question
// We must return an array of initialised Modules
// Be warned, I am writing this off of the top of my head, so excuse any syntax errors there might be!
- (NSArray *)extraModulesForBridge:(RCTBridge *)bridge

   return @[[OurNativeModule alloc] initWithCustomInitialiser:customDependency]];

编辑:我将此添加到 React-native 文档中。 https://facebook.github.io/react-native/docs/native-modules-ios.html#dependency-injection

【讨论】:

我实际上是自己发现的,但是在使用 Swift 时找不到创建 RCTModule 的好方法(我认为是 RCTModule,这是不久前的事了),因为我们的整个应用程序都是基于 Swift 的.但是,我可能会重新审视这一点,只使用目标 C 进行管道,并在 swift 中编写实际的本机模块。你搞定了吗? 是否有任何功能可以用我自己的实现替换像 DatePickerIOS 这样的标准原生模块,它使用私有 API 之类的东西来更改选择器颜色? 我开始走这条路(在 Swift 中使用 @jarora 的解决方案),但在调试后发现 React Native 不能可靠地使用模块初始化程序提供的模块。桥将使用默认初始化程序(init 不带参数)创建我的模块的第二个实例,然后使用该实例。重新加载后使用我的自定义网桥(在application:didFinishLaunchingWithOptions: 创建)也有问题。 有人有这方面的完整例子吗?我不知道在哪里上课?以及如何处理 AppDelegate.m【参考方案2】:

上面的代码运行良好。这是 Swift 4 版本的代码。

@objc(RNModuleInitialiser)
final class RNModuleInitialiser: NSObject 

    //Inject your dependencies here
    init() 

    



extension RNModuleInitialiser: RCTBridgeDelegate 

    func sourceURL(for bridge: RCTBridge!) -> URL! 
        return URL(string: "http://localhost:8081/index.ios.bundle?platform=ios")!
    

    func extraModules(for bridge: RCTBridge!) -> [RCTBridgeModule]! 

        var extraModules = [RCTBridgeModule]()

        //Initialise the modules here using the dependencies injected above

        return extraModules
    


初始化网桥时,传递moduleInitialiser:

//Make sure to hold the strong reference to the moduleInitaliser

self.moduleInitialiser = RNModuleInitialiser()
self.bridge = RCTBridge(delegate: self.moduleInitialiser, launchOptions: nil)

【讨论】:

"确保持有对 moduleInitaliser 的强引用";这解决了我的应用程序中的一个令人耳目一新的问题。感谢您的提示 如何在 React Native 端调用它?我们是否也需要为此初始化器编写桥接器?很高兴有一个完整的例子 @evanjmg 这可能会有所帮助reactnative.dev/docs/… 文档没有帮助 - 你能用注入你添加的额外模块的实际依赖项来更新这个例子吗? 链接中提到了如何使用 RCT_EXPORT_MODULE,reactnative.dev/docs/native-modules-ios#module-name@evanjmg

以上是关于React Native 模块中的依赖注入的主要内容,如果未能解决你的问题,请参考以下文章

角度 6 依赖注入

译 Node.js 中的依赖注入

如何解决 ASP.NET Core 中的依赖问题

Maven模块化开发,spring无法注入其它模块中的接口

React Native iOS 模块 Pod 依赖

2.3了解AngularJS模块和依赖注入