Инъекция зависимостей в реактивных родственных модулях

Мы проводим постепенное преобразование моего приложения в React Native. И я все время сталкиваюсь с проблемами с Injection Dependency in React Native на iOS.

У меня есть некоторые услуги в моем приложении, которое я хотел бы использовать в собственном модуле. В настоящее время они вводятся через Typhoon, и все работает отлично.

Однако сама реакция native сама инициализирует и поддерживает любой собственный модуль в виде одноэлементного. Это мешает мне позволить Typhoon инициализировать их, и поэтому я не могу вводить в них зависимости.

Что можно сделать? Создание самого RCTBridge - это вариант, но он чувствует себя очень низкоуровневым и по-прежнему нужно выяснить, как вставить его в UIView в первую очередь.

Ответы

Ответ 1

Я не совсем уверен, почему ваш вопрос не получил больше голосов; Я сам пытался ответить на один и тот же вопрос и подумал, что я должен прыгнуть и ответить на мой первый вопрос StackOverflow!

Выкапывая класс RCTBridge, предоставили ответ. Что вам нужно сделать, это инициализировать RCTBridge вручную с помощью экземпляра класса, который реализует RCTBridgeProtocol (и, что немаловажно, метод 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

Ответ 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
    }

}

При инициализации моста пройдите модульInitialiser:

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

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