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 参数,处理完成后调用 resolve 或 reject 传递数据。注意,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 适用于单次数据传递,而事件发送支持多次传递,适合实时交互场景。在实际开发中,根据需求选择合适方式,确保数据传递的效率和可靠性。