Native module's first example showcase incorrect usage of `REACT_METHOD`. It's paired with a method without a promise as one its argument
Page url
https://microsoft.github.io/react-native-windows/docs/native-modules
Problem Description
REACT_METHOD requires a promise as one of the arguments, but the doc sample at "1. Authoring your Native Module" has the following methods
REACT_METHOD(Add, L"add");
double Add(double a, double b) noexcept
{
double result = a + b;
AddEvent(result);
return result;
}
which, when it is paired with the following ts, isn't working:
const math = NativeModules.FancyMath
const value = math.add(1, 0)
console.log(`value=${value}`);
// Output value=undefined
Changing the above code as follows fixes the issue:
// c++
REACT_METHOD(Add, L"add");
void Add(double a, double b, winrt::Microsoft::ReactNative::ReactPromise<double>&& result) noexcept
{
result.Resolve(a + b);
}
// typescript
const math = NativeModules.FancyMath
const value = await math.add(1, 0)
console.log(`value=${value}`);
// Output value = 1
How I Discovered The Issue
Reading the doc, I thought 0-arity method would work like so:
// .cpp
REACT_METHOD(Test, "test")
JSValue Test() noexcept
{
return {};
}
// .tsx
const module = NativeModules.MyModule
const value = module.test()
However, upon debugging, an exception is thrown at CxxNativeModule.cpp instead:
The intended exception message was "Expected 1 callbacks, but only 0 parameters provided".
Note that I did read REACT_METHOD was async and REACT_SYNC_METHOD was synchronous. But that double Add(double, double) example above mislead me into writing the above code.
Suggested fix
Replace
REACT_METHOD(Add, L"add");
double Add(double a, double b) noexcept
{
double result = a + b;
AddEvent(result);
return result;
}
with
REACT_METHOD(Add, L"add");
void Add(double a, double b, winrt::Microsoft::ReactNative::ReactPromise<double>&& promise) noexcept
{
double result = a + b;
AddEvent(result);
promise.Resolve(result);
}
Info
System:
OS: Windows 10 10.0.22000
CPU: (16) x64 AMD Ryzen 7 2700X Eight-Core Processor
Memory: 6.66 GB / 15.92 GB
Binaries:
Node: 14.18.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.19.1 - C:\Program Files (x86)\Yarn\bin\yarn.CMD
npm: 6.14.15 - C:\Program Files\nodejs\npm.CMD
Watchman: Not Found
SDKs:
Android SDK:
API Levels: 27, 28, 29, 30
Build Tools: 28.0.3, 29.0.2, 29.0.3
Android NDK: Not Found
Windows SDK:
AllowDevelopmentWithoutDevLicense: Enabled
AllowAllTrustedApps: Enabled
Versions: 10.0.16299.0, 10.0.17763.0, 10.0.18362.0, 10.0.19041.0, 10.0.22000.0
IDEs:
Android Studio: Version 4.1.0.0 AI-201.8743.12.41.6858069
Visual Studio: 16.11.31729.503 (Visual Studio Community 2019), 17.0.31410.414 (Visual Studio Community 2022)
Languages:
Java: 1.8.0_262 - C:\Program Files\AdoptOpenJDK\jdk-8.0.262.10-hotspot\bin\javac.EXE
Python: 3.7.3 - C:\Users\Name\AppData\Local\Programs\Python\Python37\python.EXE
npmPackages:
@react-native-community/cli: Not Found
react: 16.13.1 => 16.13.1
react-native: 0.63.4 => 0.63.4
react-native-windows: 0.63.41 => 0.63.41
npmGlobalPackages:
*react-native*: Not Found
The REACT_METHOD macro works with a return value (no promise) when the JS side is using the method via a callback, like: https://github.com/microsoft/react-native-windows/blob/main/packages/sample-apps/index.windows.js#L214
However, it won't work if you are trying to use it in an await, but the docs don't clarify this distinction.
So the docs are "right" as long as you use callbacks, not await : ) It's worth then clarifying this in the docs though. Mind adding that blurb? :)