-
I've been studying from ExecuteJsiTests.cpp to try to work out how to build a JSI-based native module. Unfortunately, although this file shows how to call I've also tried creating a JSI-based module using a manually-written Spec (as I don't understand any of the Codegen instructions), based on NativeBlobModuleSpec.g.h and BlobModule.h. However, On iOS and macOS, it's quite simple to write a JSI-based native module without Codegen and without Fabric. How would I do that in React Native Windows? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 4 replies
-
I came up with one possible approach. We declare the native class for our HostObject ( ReactNativeModule.hHere's the native module code: #pragma once
#include <JSI/JsiApiContext.h>
#include <jsi/jsi.h>
#include "JSValue.h"
#include "NativeModules.h"
using namespace winrt::Microsoft::ReactNative;
using namespace facebook;
namespace winrt::Banana {
REACT_MODULE(ReactNativeModule, L"Banana")
struct ReactNativeModule {
REACT_INIT(Initialize)
void Initialize(ReactContext const& reactContext) noexcept {
m_reactContext = reactContext;
// Installing JSI HostObjects on the global context during the Initialize
// hook is legitimate:
// https://github.com/microsoft/react-native-windows/blob/3cec3f09dd0450d58fb6df284d1eb901495914b2/vnext/Shared/Modules/BlobModule.cpp#L45
ExecuteJsi(reactContext, [](jsi::Runtime& rt) {
// Declaring a HostObject class inside an ExecuteJsi block is also
// legitimate:
// https://github.com/microsoft/react-native-windows/blob/3cec3f09dd0450d58fb6df284d1eb901495914b2/vnext/Microsoft.ReactNative.IntegrationTests/ExecuteJsiTests.cpp#L55
class BananaHostObject : public jsi::HostObject {
jsi::Value get(jsi::Runtime& rt,
const jsi::PropNameID& propName) override {
std::string name = propName.utf8(rt);
if (name == "getColor") {
return jsi::Function::createFromHostFunction(
rt, jsi::PropNameID::forAscii(rt, name), 0,
[this](jsi::Runtime& rt, const jsi::Value& thisValue,
const jsi::Value* arguments,
size_t) -> jsi::Value {
return jsi::String::createFromAscii(
rt, "yellow");
});
}
return jsi::Value::undefined();
}
void set(jsi::Runtime&, const jsi::PropNameID&,
const jsi::Value&) override {}
};
// Install our native BananaHostObject class onto the JS global:
rt.global().setProperty(
rt, "Banana",
jsi::Object::createFromHostObject(
rt, std::make_shared<BananaHostObject>()));
});
}
private:
ReactContext m_reactContext{nullptr};
};
} // namespace winrt::Banana banana.tsHere's how to call it in JavaScript-land: import { TurboModuleRegistry } from "react-native";
function initializeBananaNativeModule(){
// Calling this lazy-inits our TurboModule, calling the Initialize() method
// on ReactNativeModule.h, which installs our Banana HostObject onto the JS global.
TurboModuleRegistry.get("Banana");
}
function getBananaColor(){
// It's safe to call this more than once (and only does any work on the first call).
initializeBananaNativeModule();
return global.Banana.getColor();
} Is there a more idiomatic approach than this, though? It seems a bit strange to do this all inline inside an And is it necessary to declare the classes inside the EDIT: Indeed, I've found that you can declare them in separate files just fine. |
Beta Was this translation helpful? Give feedback.
-
If you have a module written as a #include <TurboModuleProvider.h>
struct MySimpleTurboModule : facebook::react::TurboModule {
....
};
struct MySimpleTurboModulePackageProvider
: winrt::implements<MySimpleTurboModulePackageProvider, IReactPackageProvider> {
void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept {
AddTurboModuleProvider<MySimpleTurboModule>(packageBuilder, L"MySimpleTurboModule");
}
}; |
Beta Was this translation helpful? Give feedback.
-
Please check this test instead: https://github.com/microsoft/react-native-windows/blob/main/vnext/Microsoft.ReactNative.IntegrationTests/JsiTurboModuleTests.cpp The code in https://github.com/microsoft/react-native-windows/blob/main/vnext/Microsoft.ReactNative.IntegrationTests/ExecuteJsiTests.cpp shows how to use JSI in context of attributed Turbo Modules (they are designed after the Java and Objective-C Turbo Modules), not how to use the JSI Turbo Modules. |
Beta Was this translation helpful? Give feedback.
Please check this test instead: https://github.com/microsoft/react-native-windows/blob/main/vnext/Microsoft.ReactNative.IntegrationTests/JsiTurboModuleTests.cpp
It is an example how to apply @acoates-ms suggestion.
The code in https://github.com/microsoft/react-native-windows/blob/main/vnext/Microsoft.ReactNative.IntegrationTests/ExecuteJsiTests.cpp shows how to use JSI in context of attributed Turbo Modules (they are designed after the Java and Objective-C Turbo Modules), not how to use the JSI Turbo Modules.