简体   繁体   English

React Native模块中的依赖注入

[英]Dependency Injection in React Native modules

We're going through a gradual conversion of my application to React Native. 我们正在逐步将我的应用程序转换为React Native。 And I keep getting into problems with Dependency Injection in React Native on iOS. 我一直在iOS上的React Native中遇到依赖注入问题。

I have some services in my app I'd like to use in a native module. 我在我的应用程序中有一些服务,我想在本机模块中使用。 Currently, they are injected through Typhoon and everything works just fine. 目前,它们是通过台风注入的,一切正常。

However, react native itself initializes and maintains any native module as a singleton. 但是,react native本身会将任何本机模块初始化并维护为单例。 That prevents me from letting Typhoon initialize them, and so I can't inject dependencies into them. 这使我无法让Typhoon初始化它们,因此我无法将依赖关系注入其中。

What can be done? 可以做些什么? Creating the RCTBridge myself is an option, but feels very low-level, and still need to figure out how to inject it into the UIView in the first place. 自己创建RCTBridge是一个选项,但感觉非常低级,并且仍然需要弄清楚如何将其注入到UIView中。

I'm not exactly sure why your question didn't receive more up-votes; 我不确定为什么你的问题没有获得更多的选票; I myself was struggling to answer the same question and thought I should hop on and answer my first StackOverflow question! 我自己也在努力回答同样的问题,并认为我应该继续回答我的第一个StackOverflow问题!

Digging around the RCTBridge class provided the answer. 围绕RCTBridge类进行挖掘提供了答案。 What you need to do is initialise a RCTBridge manually with an instance of a class that implements the RCTBridgeProtocol (and importantly the method 'extraModulesForBridge'; you could even implement this protocol in your View Controller if you wanted to. 您需要做的是使用实现RCTBridgeProtocol的类的实例手动初始化RCTBridge(重要的是方法'extraModulesForBridge';如果您愿意,甚至可以在View Controller中实现此协议。

// 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]];
}

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

The code above works just fine. 上面的代码工作得很好。 Here's the Swift 4 version of the code. 这是代码的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
    }

}

When initializing the bridge, pass the moduleInitialiser: 初始化桥时,传递moduleInitialiser:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM