react-native-worklets-core can be used either as a standalone library to run Worklets on a background context, or as an integration with another third-party library to run code on a custom context.
To run any JS Function on a background Thread, convert it to a worklet. As an example, this is how you can compute the fibonacci sequence in JS, without blocking the main JS Thread:
const fibonacci = (num: number): number => {
'worklet'
if (num <= 1) return num;
let prev = 0, curr = 1;
for (let i = 2; i <= num; i++) {
let next = prev + curr;
prev = curr;
curr = next;
}
return curr;
}
const context = Worklets.defaultContext
const result = await context.runAsync(() => {
'worklet'
return fibonacci(50)
})
console.log(`Fibonacci of 50 is ${result}`)
Use runOnJS
to call back to JS:
const [age, setAge] = useState(30)
function something() {
'worklet'
Worklets.runOnJS(() => setAge(50))
}
Both the runAsync
and runOnJS
functions are convenience methods for createRunAsync
and createRunOnJS
. For frequent calls, prefer the prepare...
equivalent instead to memoize the caller function.
Worklets also provides three utility hooks:
Uses a memoized Worklet that can be called from the JS context, or from within another Worklet context:
function App() {
const worklet = useWorklet('default', () => {
'worklet'
console.log("hello from worklet!")
}, [])
worklet()
}
Uses a memoized callback to the JS context that can be called from within a Worklet context:
function App() {
const sayHello = useRunOnJS(() => {
console.log("hello from JS!")
}, [])
const worklet = useWorklet('default', () => {
'worklet'
console.log("hello from worklet!")
sayHello()
}, [sayHello])
worklet()
}
Uses a SharedValue instance that can be read from- and written to by both a JS context and a Worklet context at the same time:
function App() {
const something = useSharedValue(5)
const worklet = useWorklet('default', () => {
'worklet'
something.value = Math.random()
}, [something])
}
The SharedValue will create a C++ based Proxy implementation for Arrays and Objects, so that any read- or write-operations on the Array/Object are thread-safe.
You can also create specific contexts (Threads) to run Worklets on:
const context1 = Worklets.createContext('my-new-thread-1')
context1.runAsync(() => {
'worklet'
console.log("Hello from context #1!")
})
...and even nest them without ever crossing the JavaScript Thread:
const context1 = Worklets.createContext('my-new-thread-1')
const context2 = Worklets.createContext('my-new-thread-2')
context1.runAsync(() => {
'worklet'
console.log("Hello from context #1!")
context2.runAsync(() => {
'worklet'
console.log("Hello from context #2!")
})
})
To integrate react-native-worklets-core in your library, first install the package:
- Add
react-native-worklets-core
to your podspec:s.dependency "react-native-worklets-core"
- Add
react-native-worklets-core
to yourbuild.gradle
:implementation project(":react-native-worklets-core")
- Add
react-native-worklets-core
to yourCMakeLists.txt
:find_package(react-native-worklets-core REQUIRED CONFIG) # ... target_link_libraries( ${PACKAGE_NAME} # ... other libs react-native-worklets-core::rnworklets )
Then, from C++ you can convert Functions to Worklets and call them on any Thread:
- Include the Headers:
#include <JsiWorkletContext.h> #include <JsiWorklet.h>
- On the main JavaScript Thread (
mqt_js
), create your Worklet Context:auto jsCallInvoker = ... // <-- facebook::react::CallInvoker auto customThread = ... // <-- your custom Thread auto runOnJS = [jsCallInvoker](std::function<void()>&& f) { // Run on React JS Runtime jsCallInvoker->invokeAsync(std::move(f)); }; auto runOnWorklet = [customThread](std::function<void()>&& f) { // Run on your custom Thread customThread->invokeAsync(std::move(f)); }; _workletContext = std::make_shared<RNWorklet::JsiWorkletContext>("MyLibrary"); _workletContext->initialize("MyLibrary", jsRuntime, runOnJS, runOnWorklet);
- When a user passes a
jsi::Function
with the'worklet'
directive, you can convert that to a worklet:auto runtime = ... // <-- source jsi::Runtime (main JS) auto func = ... // <-- JS with 'worklet' auto worklet = std::make_shared<RNWorklet::JsiWorklet>(runtime, func); auto workletInvoker = std::make_shared<RNWorklet::WorkletInvoker>(worklet);
- Call it on your custom Thread:
_workletContext->invokeOnWorkletThread([=](RNWorklet::JsiWorkletContext*, jsi::Runtime& rt) { jsi::Value someValue(true); workletInvoker->call(rt, jsi::Value::undefined(), &someValue, 1); });