-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR adds a Worklets explaination page which is a _highly simplified_ but _extended_ version of [Fundamentals/Worklets](https://docs.swmansion.com/react-native-reanimated/docs/2.x/fundamentals/worklets) page from Reanimated v2 documentation. Requested by @piaskowyk --------- Co-authored-by: Tomek Zawadzki <[email protected]> Co-authored-by: Mikołaj Szydłowski <[email protected]> Co-authored-by: Tomasz Żelawski <[email protected]>
- Loading branch information
1 parent
2d0ed0b
commit 49f6e37
Showing
3 changed files
with
178 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
--- | ||
id: worklets | ||
sidebar_label: Worklets | ||
sidebar_position: 1 | ||
--- | ||
|
||
# Worklets | ||
|
||
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. | ||
|
||
You can create your own worklets using the `'worklet';` directive at the top of a function. | ||
|
||
```javascript | ||
function myWorklet() { | ||
'worklet'; | ||
console.log('Hello from a worklet'); | ||
} | ||
``` | ||
|
||
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. | ||
|
||
```javascript | ||
import { useAnimatedStyle } from 'react-native-reanimated'; | ||
|
||
function App() { | ||
const style = useAnimatedStyle(() => { | ||
// Running on the UI thread | ||
return { opacity: 0.5 }; | ||
}); | ||
} | ||
``` | ||
|
||
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). | ||
|
||
You can use [`runOnUI`](/docs/threading/runOnUI) to manually schedule worklet execution on the UI thread: | ||
|
||
```javascript | ||
function myWorklet() { | ||
'worklet'; | ||
console.log('Hello from the UI thread'); | ||
} | ||
|
||
function onPress() { | ||
runOnUI(myWorklet)(); | ||
} | ||
``` | ||
|
||
You can pass arguments to worklets. | ||
|
||
```javascript | ||
function myWorklet(greeting) { | ||
'worklet'; | ||
console.log(`${greeting} from the UI thread`); | ||
} | ||
|
||
function onPress() { | ||
runOnUI(myWorklet)('Howdy'); | ||
} | ||
``` | ||
|
||
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 | ||
const width = 135.5; | ||
|
||
function otherWorklet() { | ||
'worklet'; | ||
console.log('Captured width is', width); | ||
} | ||
``` | ||
|
||
Capturing large JavaScript objects inside of a worklet can lead to performance issues. | ||
|
||
```javascript | ||
const theme = {...}; // theme is a large object | ||
|
||
function myWorklet() { | ||
'worklet'; | ||
console.log(theme.color); // 🚨 referenced `color` but captured the whole `theme` object | ||
} | ||
``` | ||
|
||
You can get around this problem by first assigning the prop you want to use to a separate variable. | ||
|
||
```javascript | ||
const theme = {...}; | ||
const color = theme.color; | ||
|
||
function myWorklet() { | ||
'worklet'; | ||
console.log(color); // ✅ captured only `color` | ||
} | ||
``` | ||
|
||
Worklets can return data within the same thread. | ||
|
||
```javascript | ||
function returningWorklet() { | ||
'worklet'; | ||
return "I'm back"; // on the UI thread | ||
} | ||
|
||
function someWorklet() { | ||
'worklet'; | ||
const what = returningWorklet(); // still on the UI thread | ||
console.log('On the UI thread, other worklet says', what); | ||
} | ||
``` | ||
|
||
To pass data between UI and JS thread we use [shared values](/docs/fundamentals/glossary#shared-value). | ||
|
||
```javascript | ||
import { useSharedValue } from 'react-native-reanimated'; | ||
|
||
function App() { | ||
const width = useSharedValue(100); | ||
|
||
function myWorklet() { | ||
'worklet'; | ||
width.value += 50; | ||
} | ||
|
||
useEffect(() => { | ||
console.log(width.value); // available on both JS and UI thread | ||
}, []); | ||
} | ||
``` | ||
|
||
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)(); // 💥 | ||
}); | ||
} | ||
``` | ||
|
||
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. | ||
|
||
You can create your own worklet runtimes with [`createWorkletRuntime`](/docs/threading/createWorkletRuntime) function. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters