Skip to content

Commit

Permalink
docs: worklets on the Web are just JavaScript functions (#6737)
Browse files Browse the repository at this point in the history
This PR explains the worklet behaviour on the Web and separates the
[Worklets
guide](https://docs.swmansion.com/react-native-reanimated/docs/guides/worklets)
into easier to reference and scan sections.

---------

Co-authored-by: Tomek Zawadzki <tomasz.zawadzki@swmansion.com>
  • Loading branch information
kacperkapusciak and tomekzaw authored Nov 21, 2024
1 parent 6fad03e commit d5789d6
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 24 deletions.
70 changes: 46 additions & 24 deletions packages/docs-reanimated/docs/guides/worklets.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ sidebar_position: 1

Worklets are short-running JavaScript functions that can run on the [UI thread](/docs/fundamentals/glossary#ui-thread). Reanimated uses worklets to calculate view styles and react to events on the UI thread.

## Defining worklets

You can create your own worklets using the `'worklet';` directive at the top of a function.

```javascript
Expand All @@ -17,6 +19,8 @@ function myWorklet() {
}
```

## Workletization

The [Reanimated Babel Plugin](https://github.com/software-mansion/react-native-reanimated/blob/main/packages/react-native-reanimated/plugin/README-dev.md#basics) looks for functions marked with the `'worklet'` directive and converts them into serializable objects. We call this process [workletization](/docs/fundamentals/glossary#to-workletize). These objects can then be copied and run over on the UI thread.

Most of the time when working with Reanimated and [Gesture Handler](https://docs.swmansion.com/react-native-gesture-handler/) the code is automatically workletized and run on the UI thread by default.
Expand All @@ -32,7 +36,7 @@ function App() {
}
```

Functions marked with `'worklet';` aren't [hoisted](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting). Besides affecting hoisting, the `'worklet';` directive has no effect on the [JavaScript thread](/docs/fundamentals/glossary#javascript-thread).
## Running worklets on the UI thread

You can use [`runOnUI`](/docs/threading/runOnUI) to manually schedule worklet execution on the UI thread:

Expand Down Expand Up @@ -60,6 +64,41 @@ function onPress() {
}
```

## Running functions from worklets

You can run functions on the JS thread from the UI thread with [`runOnJS`](/docs/threading/runOnJS). Most frequently used to call functions that aren't marked with a `'worklet';` directive (i.e. most third-party libraries) or to update the React state.

```javascript
import { router } from 'expo-router';
import { Gesture } from 'react-native-gesture-handler';

function App() {
const tap = Gesture.Tap().onEnd(() => {
// i'm a worklet too!
// highlight-next-line
runOnJS(router.back)();
});
}
```

Functions passed to `runOnJS` must be defined in the [JavaScript thread](/docs/fundamentals/glossary#javascript-thread) scope, i.e. in the component body or the global scope. This code won't work because `myFunction` is defined in the `withTiming` callback, which is only executed in the [UI thread](/docs/fundamentals/glossary#ui-thread):

```javascript
function App() {
const tap = Gesture.Tap().onEnd(() => {
// myFunction is defined on the UI thread 🚨
const myFunction = () => {};
runOnJS(myFunction)(); // 💥
});
}
```

## Hoisting

Functions marked with `'worklet';` aren't [hoisted](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting). Besides affecting hoisting, the `'worklet';` directive has no effect on the [JavaScript thread](/docs/fundamentals/glossary#javascript-thread).

## Capturing closure

Worklets are [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures). They can access variables declared outside of their own scope. Only variables referenced in the worklet body will be captured inside the worklet scope.

```javascript
Expand Down Expand Up @@ -94,6 +133,8 @@ function myWorklet() {
}
```

## Passing data to worklets

Worklets can return data within the same thread.

```javascript
Expand Down Expand Up @@ -128,32 +169,13 @@ function App() {
}
```

You can run functions on the JS thread from the UI thread with [`runOnJS`](/docs/threading/runOnJS). Most frequently used to call functions that aren't marked with a `'worklet';` directive (i.e. most third-party libraries) or to update the React state.
## Using worklets on the Web

```javascript
import { router } from 'expo-router';
import { Gesture } from 'react-native-gesture-handler';
There's no separate UI thread available on the Web. Because of that, when Reanimated runs in the browser, worklets are resolved to plain JavaScript functions.

function App() {
const tap = Gesture.Tap().onEnd(() => {
// i'm a worklet too!
// highlight-next-line
runOnJS(router.back)();
});
}
```
However, the `'worklet';` directive is still necessary on the Web, because Reanimated relies on the Babel plugin to capture dependencies inside worklet functions.

Functions passed to `runOnJS` must be defined in the [JavaScript thread](/docs/fundamentals/glossary#javascript-thread) scope, i.e. in the component body or the global scope. This code won't work because `myFunction` is defined in the `withTiming` callback, which is only executed in the [UI thread](/docs/fundamentals/glossary#ui-thread):

```javascript
function App() {
const tap = Gesture.Tap().onEnd(() => {
// myFunction is defined on the UI thread 🚨
const myFunction = () => {};
runOnJS(myFunction)(); // 💥
});
}
```
## Other worklet runtimes

Worklets can run in other runtimes than the one provided by Reanimated. For example [VisionCamera](https://github.com/mrousavy/react-native-vision-camera) and [LiveMarkdown](https://github.com/Expensify/react-native-live-markdown) create their own worklet runtimes.

Expand Down
2 changes: 2 additions & 0 deletions packages/docs-reanimated/docs/threading/runOnUI.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ import RunOnUISrc from '!!raw-loader!@site/src/examples/RunOnUI';

- Make sure not to execute `runOnUI` on the UI thread as this will result in an error.

- In browsers there's no separate UI thread available. Because of that, on the Web, `runOnUI` behaves similarly to `requestAnimationFrame`. It creates a function that, when called, will be scheduled to run with given arguments on next animation frame.

## Platform compatibility

<PlatformCompatibility android ios web />

0 comments on commit d5789d6

Please sign in to comment.