Creating Custom UI component for android on React Native. How to send data to JS?

后端 未结 2 799
[愿得一人]
[愿得一人] 2020-12-05 16:09

I create UI. It works well. But i don\'t know how to send data from Java to JS? In react native moduls I can use callback and activete this onClick events. But in UI i don\'

相关标签:
2条回答
  • 2020-12-05 16:36

    http://facebook.github.io/react-native/docs/native-components-android.html#events

    ^this shows how you can trigger events from Java side to JS on an UI component.

    but for "custom events" (events that are not pre-defined likes onLoad, onScroll, etc..) you will also need to override getExportedCustomDirectEventTypeConstants.

    Here is an example, triggering onGLProgress for gl-react-native:

    (1) define the custom event mapping: https://github.com/ProjectSeptemberInc/gl-react-native/blob/7d6e83de5a8280d06d47234fe756aa3050e9b9a1/android/src/main/java/com/projectseptember/RNGL/GLCanvasManager.java#L115-L116

    (2) dispatch the event from Java to JS: https://github.com/ProjectSeptemberInc/gl-react-native/blob/0f64a63fec2281e9d6d3641b9061b771a44fcac8/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java#L839-L849

    (3) and on the JS side, you can give a onGLProgress prop callback.

    0 讨论(0)
  • 2020-12-05 16:47

    Building on gre's answer that put me on the right track, but still left me with a lot of work to do, I'll try to explain some of the missing details.

    There are 2 basic ways to do this:

    1. use an existing event type
    2. create & use a custom event type

    Existing Events

    As gre mentioned, the React Native docs explain this in the Native UI Components section of Events.

    They show how to send the event using the following code:

      WritableMap event = Arguments.createMap();
      event.putString("message", "MyMessage");
      ReactContext reactContext = (ReactContext)getContext();
      reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
          getId(), "topChange", event);
    

    With this explanation:

    The event name topChange maps to the onChange callback prop in JavaScript (mappings are in UIManagerModuleConstants.java).

    The actual definition from UIManagerModuleConstants.java looks like this:

    "topChange",
        MapBuilder.of(
            "phasedRegistrationNames",
                MapBuilder.of(
                    "bubbled", "onChange", 
                    "captured", "onChangeCapture")))
    

    i.e. by using the event topChange in the Android code, you can intercept it in JS with either onChange or onChangeCapture due to this mapping.

    You can find many other existing events declared in there to piggy-back on.

    There are also "direct" events declared in that may be more useful:

    "topLayout", 
        MapBuilder.of("registrationName", "onLayout")
    

    i.e. Android event topLayout maps to JS event callback onLayout

    (I do not understand the difference between the "bubbled" vs "captured" vs "direct" event types)

    To receive the event in JS, take note of the 3 places _onChange() is referenced in the docs:

    1. create the callback method: _onChange(event: Event) {}

    2. bind it in the constructor: this._onChange = this._onChange.bind(this);

    3. pass it when creating your custom view: return <RCTMyCustomView {...this.props} onChange={this._onChange} />;


    Custom Events

    Custom events need to be declared to the system before they can be used, mapping Android events to JS events in a similar way to how they are done by React Native above.

    This is done by overriding one of the following methods in your ViewManager:

    • getExportedCustomBubblingEventTypeConstants()
    • getExportedCustomDirectEventTypeConstants()

    The javadoc is very helpful in showing how the mapping should work, but I found it useful to reference the React Native code in UIManagerModuleConstants mentioned above.

    Once it is declared there, you use it as you would any other "existing" event.


    Example Custom Event implementation

    I wanted to send the click event from Android up to JS, and to call it onClick. I chose to use a "direct" event for this. I also chose to use the same name in Android and in JS - this is not necessary.

    3 files need to be modified:

    ViewManager class

    This code maps the Android event name "onClick" to the JS function "onClick".

    /**
     * This method maps the sending of the "onClick" event to the JS "onClick" function.
     */
    @Nullable @Override
    public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
        return MapBuilder.<String, Object>builder()
                .put("onClick",
                        MapBuilder.of("registrationName", "onClick"))
                .build();
    }
    

    View class

    This code sends an event to the JS when the view is clicked. The name used here is the Android event name, which will map to whatever you set above in the ViewManager class.

        // trigger the onPress JS callback
        super.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                final Context context = getContext();
                if (context instanceof ReactContext) {
                    ((ReactContext) context).getJSModule(RCTEventEmitter.class)
                            .receiveEvent(getId(),
                                    "onClick", null);
                }
            }
        });
    

    The instanceof check is there because this view is sometimes referenced from native code, outside the React context.

    React Native JS component

    Bind in constructor:

      constructor(props) {
        super(props);
        this.onClick = this.onClick.bind(this);
      }
    

    Declare actual callback function:

      onClick(event: Event) {
        // do something
      }
    

    Make sure to set the callback when rendering your view:

      render() {
        return <NativeView onClick={this.onClick} />;
      }
    

    All very simple when laid out like this, but the documentation of the finer details is scattered around the web.

    0 讨论(0)
提交回复
热议问题