React Native原生模块向JS传递数据方法

Viewed 0

React Native 原生模块向 JS 传递数据的几种方式

在做 React Native 开发时,避免不了原生模块和 JS 之间进行数据传递。本文将分享原生模块向 JS 传递数据的几种常见方式。

方式一:通过 Callbacks

Callbacks 是最常用的设计模式之一,在多种编程语言中都有应用。原生模块支持 Callbacks 类型的参数,对应 JS 中的 function。

在原生模块中:

public class RNTestModule extends ReactContextBaseJavaModule {
    public RNTestModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }
    @Override
    public String getName() {
        return "RNTest";
    }
    @ReactMethod
    public void measureLayout(int tag, int ancestorTag, Callback errorCallback, Callback successCallback) {
        try {
            WritableMap map = Arguments.createMap();
            map.putDouble("relativeX", 1);
            map.putDouble("relativeY", 1);
            map.putDouble("width", 2);
            map.putDouble("height", 3);
            successCallback.invoke(map);
        } catch (IllegalViewOperationException e) {
            errorCallback.invoke(e.getMessage());
        }
    }
}

在上述代码中,measureLayout 方法的最后两个参数是 Callbacks。处理成功时通过 successCallback 回调结果,发生异常时通过 errorCallback 回调错误信息。

在 JS 模块中:

RNTest.measureLayout(
    100,
    100,
    (msg) => {
        console.log(msg);
    },
    (x, y, width, height) => {
        console.log(x + ':' + y + ':' + width + ':' + height);
    }
);

JS 调用原生模块的 measureLayout 方法,并通过 function 参数接收回调数据。这种 "You call me, I will callback" 的方式简单直接。

方式二:通过 Promises

Promises 是 ES6 的特性,在 React Native 中广泛使用。原生模块也支持 Promises。

在原生模块中:

public class RNTestModule extends ReactContextBaseJavaModule {
    public RNTestModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }
    @Override
    public String getName() {
        return "RNTest";
    }
    @ReactMethod
    public void measureLayout(int tag, int ancestorTag, Promise promise) {
        try {
            WritableMap map = Arguments.createMap();
            map.putDouble("relativeX", 1);
            map.putDouble("relativeY", 1);
            map.putDouble("width", 2);
            map.putDouble("height", 3);
            promise.resolve(map);
        } catch (IllegalViewOperationException e) {
            promise.reject(e);
        }
    }
}

measureLayout 方法接收一个 Promise 参数,处理完成后调用 resolvereject 传递数据。注意,Promise 参数应放在最后。

在 JS 模块中:

使用 async/await:

async test() {
    try {
        var { relativeX, relativeY, width, height } = await RNTest.measureLayout(100, 100);
        console.log(relativeX + ':' + relativeY + ':' + width + ':' + height);
    } catch (e) {
        console.error(e);
    }
}

或使用 then/catch:

test2() {
    RNTest.measureLayout(100, 100)
        .then(e => {
            console.log(e.relativeX + ':' + e.relativeY + ':' + e.width + ':' + e.height);
            this.setState({
                relativeX: e.relativeX,
                relativeY: e.relativeY,
                width: e.width,
                height: e.height,
            });
        })
        .catch(error => {
            console.log(error);
        });
}

Promises 方式允许以同步或异步形式处理结果,适用于单次数据传递。

方式三:通过发送事件

原生模块可以通过发送事件向 JS 模块传递数据,类似于广播或通知中心,支持多次传递。

在原生模块中:

@Override
public void onHandleResult(String barcodeData) {
    WritableMap params = Arguments.createMap();
    params.putString("result", barcodeData);
    sendEvent(getReactApplicationContext(), "onScanningResult", params);
}

private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
    reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
            .emit(eventName, params);
}

发送名为 onScanningResult 的事件并携带参数,JS 模块可以监听并处理。

在 JS 模块中:

componentDidMount() {
    DeviceEventEmitter.addListener('onScanningResult', this.onScanningResult);
}

onScanningResult = (e) => {
    this.setState({
        scanningResult: e.result,
    });
    // 如需移除监听:DeviceEventEmitter.removeListener('onScanningResult', this.onScanningResult);
}

JS 模块监听事件并更新状态。多处监听会同时收到事件,可通过 removeListener 移除监听。

总结

以上介绍了 React Native 原生模块向 JS 传递数据的三种方式:Callbacks、Promises 和事件发送。Callbacks 和 Promises 适用于单次数据传递,而事件发送支持多次传递,适合实时交互场景。在实际开发中,根据需求选择合适方式,确保数据传递的效率和可靠性。

0 Answers