React Native 中的 Native 模块:function returns "undefined"
Native module in React Native: function returns "undefined"
所以,我正在练习在 Java 中制作原生模块,这些模块可以将函数暴露给 React Native 的 JavaScript 代码。为此,我决定使用一个简单的演示数学库。我的代码如下。
MathOpsModule.java
package com.mb_rn_poc;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class MathOpsModule extends ReactContextBaseJavaModule {
@Override
public String getName() {
return "MathOps"; // Name of the Native Modules.
}
@ReactMethod
public int add(int a, int b) {
return (a + b);
}
}
MathOpsPackage.java
package com.mb_rn_poc;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MathOpsPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext
) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext
) {
List<NativeModule> modules = new ArrayList<>();
// Register the MathOps module
modules.add(new MathOpsModule());
return modules;
}
}
MainApplication.java
package com.mb_rn_poc;
import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new MathOpsPackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.mb_rn_poc.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
现在,在 React Native 方面,我有这两个文件 -
MathOps.js
import { NativeModules } from 'react-native';
const MathOps = NativeModules.MathOps;
export const add = (a, b) => {
return MathOps.add(a, b);
}
MainApp.js
import React, { useEffect, useState } from 'react';
import { SafeAreaView, Text, View } from 'react-native';
import { add } from "./NativeWrapper/MathOps";
const MainApp = () => {
const [state, setState] = useState(0);
useEffect(() => {
let sum = add(10, 12);
console.log({ sum });
setState(sum);
}, [])
return (
<SafeAreaView>
<View>
<Text>
{state}
</Text>
</View>
</SafeAreaView>
);
}
export default MainApp;
问题是,add
函数返回 undefined
。因此,屏幕上不会打印任何内容。知道我可能做错了什么吗?
不确定这是什么问题,但有一个解决方法 - 使用回调,如 https://reactnative.dev/docs/native-modules-android 中所述。我做了以下修改-
@ReactMethod
public void add(Double a, Double b, Callback cb) {
Double sum = a + b;
cb.invoke(sum);
}
import { /* ... */ NativeModules } from 'react-native';
const { MathModule } = NativeModules;
// ...
// ...
MathModule.add(10, 20, (sum) => {
alert(sum);
})
它做了我期望的事情 - 警报“30”。
对本机方法的调用是异步的,因此它们不能直接 return 值。
您可以使用回调(如您自己所想),或使用 Promise
以允许更优雅的 async
/ await
语法(以及更多):
@ReactMethod
public void add(Double a, Double b, Promise promise) {
Double sum = a + b;
promise.resolve(sum);
}
import { NativeModules } from 'react-native';
const { MathOps } = NativeModules;
export const add = async (a, b) => {
return await MathOps.add(a, b);
}
React Native 桥是异步的。我们可以通过以下方式将数据从 Native Side 传递到 Javascript:-
1)Promise:当一个native模块Java/Kotlin方法的最后一个参数是一个Promise时,它对应的JS方法会return一个JS Promise对象。
在Module.java->
@ReactMethod
public void add(Double a, Double b, Promise promise) {
Double sum = a + b;
promise.resolve(sum);
}
这就是您在 Javascript->
中访问的方式
import { NativeModules } from 'react-native';
const { MathOps } = NativeModules;
export const add = async (a, b) => {
return await MathOps.add(a, b);
}
2。 Callback: 它们也可以用于从本机端异步执行JavaScript。
在Module.java->
@ReactMethod
public void add(Double a, Double b, Callback cb) {
Double sum = a + b;
cb.invoke(sum);
}
这就是您在 Javascript->
中访问的方式
import { NativeModules } from 'react-native';
const { MathOps } = NativeModules;
useEffect(() => {
MathOps.add(10, 12, (sum) => {
setState(sum);
});
}, [])
3。 isBlockingSynchronousMethod(由于性能损失和本机模块的 threading-related 错误,不推荐):您可以将 isBlockingSynchronousMethod = true 传递给本机方法以将其标记为同步方法。
@ReactMethod(isBlockingSynchronousMethod = true)
public Double add(Double a, Double b){
Double sum = a + b;
return sum;
}
在js文件中:
import { NativeModules } from 'react-native';
const { MathOps } = NativeModules;
export const add = async (a, b) => {
return await MathOps.add(a, b);
}
4。发射事件:还没有探索太多。
所以,我正在练习在 Java 中制作原生模块,这些模块可以将函数暴露给 React Native 的 JavaScript 代码。为此,我决定使用一个简单的演示数学库。我的代码如下。
MathOpsModule.java
package com.mb_rn_poc;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class MathOpsModule extends ReactContextBaseJavaModule {
@Override
public String getName() {
return "MathOps"; // Name of the Native Modules.
}
@ReactMethod
public int add(int a, int b) {
return (a + b);
}
}
MathOpsPackage.java
package com.mb_rn_poc;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MathOpsPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext
) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext
) {
List<NativeModule> modules = new ArrayList<>();
// Register the MathOps module
modules.add(new MathOpsModule());
return modules;
}
}
MainApplication.java
package com.mb_rn_poc;
import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new MathOpsPackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.mb_rn_poc.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
现在,在 React Native 方面,我有这两个文件 -
MathOps.js
import { NativeModules } from 'react-native';
const MathOps = NativeModules.MathOps;
export const add = (a, b) => {
return MathOps.add(a, b);
}
MainApp.js
import React, { useEffect, useState } from 'react';
import { SafeAreaView, Text, View } from 'react-native';
import { add } from "./NativeWrapper/MathOps";
const MainApp = () => {
const [state, setState] = useState(0);
useEffect(() => {
let sum = add(10, 12);
console.log({ sum });
setState(sum);
}, [])
return (
<SafeAreaView>
<View>
<Text>
{state}
</Text>
</View>
</SafeAreaView>
);
}
export default MainApp;
问题是,add
函数返回 undefined
。因此,屏幕上不会打印任何内容。知道我可能做错了什么吗?
不确定这是什么问题,但有一个解决方法 - 使用回调,如 https://reactnative.dev/docs/native-modules-android 中所述。我做了以下修改-
@ReactMethod
public void add(Double a, Double b, Callback cb) {
Double sum = a + b;
cb.invoke(sum);
}
import { /* ... */ NativeModules } from 'react-native';
const { MathModule } = NativeModules;
// ...
// ...
MathModule.add(10, 20, (sum) => {
alert(sum);
})
它做了我期望的事情 - 警报“30”。
对本机方法的调用是异步的,因此它们不能直接 return 值。
您可以使用回调(如您自己所想),或使用 Promise
以允许更优雅的 async
/ await
语法(以及更多):
@ReactMethod
public void add(Double a, Double b, Promise promise) {
Double sum = a + b;
promise.resolve(sum);
}
import { NativeModules } from 'react-native';
const { MathOps } = NativeModules;
export const add = async (a, b) => {
return await MathOps.add(a, b);
}
React Native 桥是异步的。我们可以通过以下方式将数据从 Native Side 传递到 Javascript:-
1)Promise:当一个native模块Java/Kotlin方法的最后一个参数是一个Promise时,它对应的JS方法会return一个JS Promise对象。
在Module.java->
@ReactMethod
public void add(Double a, Double b, Promise promise) {
Double sum = a + b;
promise.resolve(sum);
}
这就是您在 Javascript->
中访问的方式import { NativeModules } from 'react-native';
const { MathOps } = NativeModules;
export const add = async (a, b) => {
return await MathOps.add(a, b);
}
2。 Callback: 它们也可以用于从本机端异步执行JavaScript。
在Module.java->
@ReactMethod
public void add(Double a, Double b, Callback cb) {
Double sum = a + b;
cb.invoke(sum);
}
这就是您在 Javascript->
中访问的方式import { NativeModules } from 'react-native';
const { MathOps } = NativeModules;
useEffect(() => {
MathOps.add(10, 12, (sum) => {
setState(sum);
});
}, [])
3。 isBlockingSynchronousMethod(由于性能损失和本机模块的 threading-related 错误,不推荐):您可以将 isBlockingSynchronousMethod = true 传递给本机方法以将其标记为同步方法。
@ReactMethod(isBlockingSynchronousMethod = true)
public Double add(Double a, Double b){
Double sum = a + b;
return sum;
}
在js文件中:
import { NativeModules } from 'react-native';
const { MathOps } = NativeModules;
export const add = async (a, b) => {
return await MathOps.add(a, b);
}
4。发射事件:还没有探索太多。