简体   繁体   中英

Dismiss a React Native RCTRootView back to a Native ViewController

I'm creating an app to integrate react-native with an existing Swift app.

I've looked into similar issues:

While following different tutorials:

And the official docs

The problem is: all of them are outdated (but the docs). Most of them use the legacy Navigation rather than Stack Navigator . One of the tutorials (the one with an asterisk) shows how to dismiss the React Native app back to the Native app using the rootTag of the app, but again, this was done with the legacy Navigation .

If I try to do the same, I'm not able to see the props from my app.

I have a single Storyboard with a Button inside that when clicked calls this UIViewController :

ButtonController

import Foundation
import UIKit
import React

class ButtonController: UIViewController  {
    @IBOutlet weak var button: UIButton!

    @IBAction func buttonClicked(_ sender: Any) {
        let data:[String : String] = ["onNavigationStateChange": "{handleNavigationChange}",
                                      "uriPrefix":"/app"];
        let rootView = MixerReactModule.sharedInstance.viewForModule("ReactNativeApp", initialProperties: data)

        let viewController = UIViewController()
        viewController.view = rootView
        self.present(viewController, animated: true, completion: nil)
    }
}

And when I start the app I can see this:

2019-10-23 10:29:30.021 [info][tid:com.facebook.react.JavaScript] Running "ReactNativeApp" with {"rootTag":1,"initialProps":{"uriPrefix":"/app","onNavigationStateChange":"{handleNavigationChange}"}}

But when I try to access the this.props property on React Native code I get undefined .

index.js

import HomeScreen from './components/HomeScreen'
import {AppRegistry} from 'react-native';
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';

const MainNavigator = createStackNavigator({
  Home: {screen: HomeScreen}
}, {
  initialRouteName: 'Home'
})

const NavigationApp = createAppContainer(MainNavigator);

AppRegistry.registerComponent('ReactNativeApp', () => NavigationApp)

console.log("NANANA1", this)
console.log("NANANA2", this.routeName)
console.log("NANANA3", MainNavigator)
console.log("NANANA4", MainNavigator.props)
console.log("NANANA5", NavigationApp)
console.log("NANANA6", NavigationApp.props)

export default NavigationApp

HomeScreen.js

import React from 'react';
import {Text, View, Button, NativeModules} from 'react-native';

var RNBridge = NativeModules.RNBridge;

export default class HomeScreen extends React.Component {
    static navigationOptions = {
      headerTitle: () => (
        <Text>'Welcome'</Text>
      ),
      headerLeft: () => (
        <Button title="Dismiss" onPress={() => {
          console.log("WOLOLO: ", RNBridge)
          console.log("ROGAN: ", this._reactInternalFiber.tag)
          RNBridge.dismissPresentedViewController(this._reactInternalFiber.tag)
          // RNBridge.dismissPresentedViewController(1)
        }}/>
      )
    };
    render() {
      console.log('KIKIKI', this._reactInternalFiber.tag)
      console.log("MMMMMMM: ", this.props)
      return (
        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
          <Text>Home Screen</Text>
        </View>
      );
    }
}

These are the 2 files that I use in RN to generate my View. I've tried many things to get the rootTag value, and the only one that seems to provide this value is ( tag and rootTag on XCode are the same ( 1 ))

this._reactInternalFiber.tag

But I don't know how to send these values to my headerLeft method to use the same tag so that when I press the Dismiss button it calls the Swift code for dismissPresentedViewController .

How can I dismiss my VC effectively? Or at least get the rootTag being passed from Swift to my headerLeft() method?

I'm using these versions of react-native :

react-native-cli: 2.0.1
react-native: 0.61.2

If your are looking to dismiss the native swift view controller presented from RN View

self.dismiss(animated: true, completion: nil)

I present the swift view controller as below

 let modelVC = ModelViewController()  <-- sub class of UIViewController

 DispatchQueue.main.async {
   let navController = UINavigationController(rootViewController: modelVC)
   navController.modalPresentationStyle = .fullScreen
   let topController = UIApplication.topMostViewController()
   topController?.present(navController, animated: true, completion: nil)
 }

I have an extension on the UIApplication to find out what is the top most view controller which is used above

extension UIApplication {

  class func topMostViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {

    if let navigationController = controller as? UINavigationController {
      return topMostViewController(controller: navigationController.visibleViewController)
    }

    if let tabController = controller as? UITabBarController {
      if let selected = tabController.selectedViewController {
        return topMostViewController(controller: selected)
      }
    }

    if let presented = controller?.presentedViewController {
      return topMostViewController(controller: presented)
    }

    return controller
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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