Перейти к содержанию

runOnJS

runOnJS позволяет асинхронно запускать не workletized функции, которые иначе не могли бы выполняться в UI thread. Это относится к большинству внешних библиотек, поскольку их функции не помечены директивой "worklet";.

Функция runOnJS обычно используется для обновления состояния React либо по завершении анимации, либо условно в рамках жеста.

Справочник

1
2
3
4
5
6
import { runOnJS } from 'react-native-reanimated';

function App() {
    // While on the UI thread
    runOnJS(navigation.goBack)();
}

Определения типов

1
2
3
function runOnJS<A extends any[], R>(
    fn: (...args: A) => R
): (...args: Parameters<typeof fn>) => void;

Аргументы

fn

Ссылка на функцию, которую необходимо выполнить в JavaScript-потоке из UI-потока. Аргументы вашей функции должны быть переданы в функцию, возвращаемую из runOnJS, т.е. runOnJS(setValue)(10);.

Возвращает

runOnJS возвращает функцию, принимающую аргументы для функции, переданной в качестве первого аргумента. Эта функция может быть безопасно выполнена в потоке UI.

Не забудьте вызвать функцию, возвращаемую из runOnJS.

Пример

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import React from 'react';
import {
    Button,
    View,
    StyleSheet,
    Text,
} from 'react-native';
import Animated, {
    useSharedValue,
    withSpring,
    runOnJS,
} from 'react-native-reanimated';
import { useAnimatedStyle } from 'react-native-reanimated';

export default function App() {
    const scale = useSharedValue(1);
    const [finished, setFinished] = React.useState(false);

    const handlePress = () => {
        scale.value = withSpring(2, {}, () => {
            // highlight-next-line
            runOnJS(setFinished)(true);
        });
    };

    const animatedStyle = useAnimatedStyle(() => ({
        transform: [{ scale: scale.value }],
    }));

    return (
        <View style={styles.container}>
            <Animated.View
                style={[styles.box, animatedStyle]}
            />
            <Button
                onPress={handlePress}
                title="Click me"
                disabled={finished}
            />
            {finished && <Text>Finished! 🎉</Text>}
        </View>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
    },
    box: {
        height: 100,
        width: 100,
        backgroundColor: '#b58df1',
        borderRadius: 20,
        marginVertical: 64,
        alignSelf: 'center',
    },
});

Замечания

  • Функции, передаваемые в runOnJS, должны быть определены в области JavaScript thread, т.е. в теле компонента или в глобальной области. Данный код не будет работать, поскольку myFunction определена в обратном вызове withTiming, который выполняется только в потоке UI thread:

    1
    2
    3
    4
    5
    6
    7
    withTiming(0, {}, () => {
        // myFunction is defined on the UI thread
        const myFunction = () => {
            // ...
        };
        runOnJS(myFunction)(); // 💥
    });
    
  • Распространенной ошибкой является выполнение функции внутри runOnJS следующим образом: runOnJS(setValue(10))(). Здесь правильным будет runOnJS(setValue)(10).

  • Безопасно запускать функции через runOnJS в JavaScript-потоке, так как это не оказывает никакого влияния.

Совместимость с платформами

Android iOS Web

Ссылки

Комментарии