How to control the existing React Native view instance from another native module
Tags: reactnative
Published: 2021-02-19 13:36:41

I've written how to inter-communicate between native modules in a React Native project:

{% post craftzdog/inter-communication-between-native-modules-on-react-native-57bn %}

Now, it's possible to get a View instance from another native module.
That allows you to control the existing view such as injecting JS into WebView without going through the React Native JS bridge, which is way performant.

## Get React View Tag

Every view component has a react tag, which is a view instance identifier managed by `RCTUIManager` in iOS and `UIManagerModule` in Android.
You can get a view tag in the JS app like so:

```js
import { WebView } from 'react-native-webview'

const YourComponent = (props) => {
  const webViewRef = useRef()
  useEffect(() => {
    const { current: webView } = webViewRef
    if (webView) {
      console.log(webView.webViewRef.current._nativeTag)
    }
  }, [])

  return (
    <WebView
      ref={webViewRef}
      ...
    />
  )
}
```

Well, let's get the view instance from your native module.

## iOS

`RCTUIManager` provides a method to get a view instance from a react tag:

```objc
- (UIView *)viewForReactTag:(NSNumber *)reactTag
```

Prepare your bridge module to have access to the `RCTBridge` by following the steps described in the above post.
In your native bridge, you have to run on the main queue because views should be always controlled on the same thread.
For example, you can get an instance of WebView component by `reactTag` like so:

```objc
#import <React/RCTUIManager.h>

RCT_EXPORT_METHOD(runJS:(NSString* __nonnull)js
                  inView:(NSNumber* __nonnull)reactTag
                  withResolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
  RCTUnsafeExecuteOnMainQueueSync(^{
    RCTUIManager* uiManager = [self.bridge moduleForClass:[RCTUIManager class]];
    RNCWebView* webView = (RNCWebView*)[uiManager viewForReactTag:reactTag];
    if (webView) {
      [webView injectJavaScript:js];
    }
    resolve(@"OK");
  });
}
```

It runs the given JS code in the webview with the specified tag.

## Android

`UIManagerModule` provides a method to get a view instance from a react tag:

```java
public View resolveView(int tag)
```

As described in the above post, you can get an instance of `UIManagerModule` from `reactContext`.
Then, you can get a view by doing so:

```java
  @ReactMethod
  public void injectJavaScript(int reactTag, String js) {
      UIManagerModule uiManagerModule = this.reactContext.getNativeModule(UIManagerModule.class);
      WebView webView = (WebView) uiManagerModule.resolveView(reactTag);
      webView.post(new Runnable() {
          @Override
          public void run() {
              webView.evaluateJavascript(js, null);
          }
      });
  }
```

Now you can control the existing views from your native module.
Hope that helps!

* * *

- Follow me on [Twitter](https://twitter.com/inkdrop_app) & [Instagram](https://instagram.com/craftzdog)
- [Inkdrop — Markdown note-taking app](https://www.inkdrop.app/)
- [Solo developer's Discord community](https://discord.gg/S7hDmvh)

[![Subscribe Newsletter](https://miro.medium.com/proxy/1*-J5tp1_lulY9QknoLEv6zA.png)](http://eepurl.com/dNgJo6)

[![My YouTube channel](https://miro.medium.com/proxy/1*r-daItizHpAU-fQZk3ISag.png)](https://www.youtube.com/c/devaslife)