16

We can control custom native UI components' properties by exporting native properties using RCT_EXPORT_VIEW_PROPERTY.

But how to export instance methods of native UI components?

Derek Hsu
  • 1,158
  • 11
  • 15

2 Answers2

16

Thanks to @alinz's suggestion.

This can be done within the custom native component's view manager.

  1. Obj-c side: In the native view manager expose a native method like this:

The key is to pass in the reactTag which is the reference to the native component.

MyCoolViewManager.m:

RCT_EXPORT_METHOD(myCoolMethod:(NSNumber *)reactTag callback:(RCTResponseSenderBlock)callback) {
  [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
    MyCoolView *view = viewRegistry[reactTag];
    if (![view isKindOfClass:[MyCoolView class]]) {
      RCTLogMustFix(@"Invalid view returned from registry, expecting MyCoolView, got: %@", view);
    }
    // Call your native component's method here
    [view myCoolMethod];
  }];
}
  1. JS side: Add API in the react component class:

MyCoolView.js:

var React = require('react-native');
var NativeModules = require('NativeModules');
var MyCoolViewManager = NativeModules.MyCoolViewManager;
var findNodeHandle = require('findNodeHandle');

class MyCoolView extends React.Component{
    // ...
    myCoolMethod() {
        return new Promise((resolve, reject) => {
            MyCoolViewManager.myCoolMethod(
                findNodeHandle(this),
                (error, result) => {
                    if (error) {
                        reject(error);
                    } else {
                        resolve(result);
                    }
                }
            );
        });
    }
}
Derek Hsu
  • 1,158
  • 11
  • 15
  • 4
    This solution doesn't seem to work with new version of react native. addUIBlock is no longer callable from uiManager. Trying figure out how to resolve this. – Patm Mar 14 '16 at 16:57
  • 2
    I found a working example on github. Check it out. https://github.com/ProjectSeptemberInc/gl-react-native/blob/master/ios/GLCanvasManager.m#L38 – Daigo Sato Feb 03 '17 at 00:01
  • 1
    FYI, I needed this for Android, and posted solution here: https://stackoverflow.com/a/45684685/194065 – Sean Adkinson Aug 14 '17 at 23:56
  • @Patm did you figure out what to do now that addUiBlock is no longer callable? – SudoPlz Mar 19 '21 at 22:46
-1

I'm not an Objective C expert but a Swift developer.

I better use this way just for readability (maybe there are drawbacks in Obj-C?):

  • In Manager: store a reference to your view in an instance private property
  • it will then help to call your view's method

Obj-C side - component manager:

@implementation RNAnalogClockManager {
  RNAnalogClock* _AnalogClock;
}

RCT_EXPORT_MODULE()

- (UIView *)view
{
  // keep a reference to the view before returning it
  _AnalogClock = [[RNAnalogClock alloc] init];
  return _AnalogClock;
}

// export method and easily call view method 
RCT_EXPORT_METHOD(startRealTime) {
  [_AnalogClock startRealTime];
};

JS side remains the same

NOTE: I don't need callback in my example but it does not change the principle it is just another parameter.

MacKentoch
  • 2,346
  • 3
  • 14
  • 19
  • what happens if the start method is called before the view method? then the _AnalogClock is nil and all things are broken.. – pvinis Nov 15 '16 at 15:48
  • Component manager is the way RN can play with native AnalogClock. View() method is called by RN to create an instance of the Native. RN can't call start timer method before it is instantiated so it can't occur. – MacKentoch Nov 15 '16 at 16:28
  • This does not seem to allow to have multiple instances of AnalogClock. – Daigo Sato Feb 03 '17 at 00:11