にょっす速報🐮✋

【Reactnative】Reanimated 2 での UI スレッドの処理と `worklet` の使い方、 runOnJSについて解説  ReanimatedError: [Reanimated] Tried to synchronously call a non-worklet function on the UI thread

この記事の目次

Reanimated 2 での UI スレッドの処理と worklet の使い方

React Native のアニメーションやジェスチャー処理を高速で行うために、Reanimated 2UI スレッドJavaScript スレッド をうまく使い分ける機能を提供しています。この中でも重要な機能が workletrunOnJS です。本記事では、これらの使い方や注意点について解説します。

worklet とは?

worklet は、React Native Reanimated 2 の UI スレッドで実行する関数 を定義するためのマークです。UI スレッド上で動作するコードはパフォーマンスが向上し、スムーズなアニメーションやジェスチャー処理を実現できます。

worklet が必要な理由

Reanimated 2 では、アニメーションやジェスチャーをUIスレッドで処理することで、パフォーマンスを大幅に向上させることができます。そのため、UIスレッドで実行したい関数には worklet を明記する必要があります。

const gesture = Gesture.Pan().onEnd(event => {
  'worklet'; // UIスレッドで動作させるために必須
  if (event.translationX > 100) {
    runOnJS(navigation.openDrawer)(); // JavaScriptスレッドでの処理に切り替え
  }
});

上記の例では、ジェスチャーの onEnd イベントを処理する関数内に 'worklet' を付けることで、UI スレッドでその関数が実行されることを指示しています。

runOnJS とは?

runOnJS は、UI スレッドで動作しているコードから JavaScript スレッドの関数を呼び出すためのメソッド です。UI スレッドで動作しているコードは高速でなければならないため、React Native の UI スレッドで完結する処理を行い、必要に応じて JavaScript スレッドに処理を移すことが求められます。

const gesture = Gesture.Pan().onEnd(event => {
  'worklet'; // UIスレッドで動作させるために必須
  if (event.translationX > 100) {
    runOnJS(navigation.openDrawer)(); // JavaScriptスレッドでの処理に切り替え
  }
});

このコードでは、ジェスチャーイベントが UI スレッドで処理される際に、スワイプ方向が右であれば runOnJS を使って JavaScript スレッドの navigation.openDrawer を実行しています。

workletrunOnJS を使うタイミング

worklet が必要な場合

  • ジェスチャー処理: ジェスチャーの位置や速度を元にアニメーションを実行する場合、UI スレッドで処理するために worklet が必要です。
  • アニメーションの管理: アニメーションの更新処理も UI スレッドで行う必要があり、これにも worklet を付けることが求められます。

runOnJS が必要な場合

  • JavaScript スレッドでの処理: UI スレッドから JavaScript スレッドの関数を呼び出すために runOnJS を使います。例えば、navigation.openDrawer() のように画面遷移を行う場合です。

よくあるエラーとその回避方法

エラー: ReanimatedError: [Reanimated] Tried to synchronously call a non-worklet function on the UI thread

このエラーは、UI スレッドから直接 JavaScript スレッドの関数を呼び出そうとした場合に発生します。解決策は、runOnJS を使って JavaScript スレッドで関数を実行することです。

// エラー発生例
const gesture = Gesture.Pan().onEnd(event => {
  if (event.translationX > 100) {
    navigation.openDrawer(); // ここでエラーが発生
  }
});

上記のコードでは、UI スレッド上で navigation.openDrawer() を呼び出そうとしているため、エラーが発生します。これを解決するために、runOnJS を使って JavaScript スレッドに移行します。

// 解決方法
const gesture = Gesture.Pan().onEnd(event => {
  'worklet'; // UIスレッドで動作させるために必須
  if (event.translationX > 100) {
    runOnJS(navigation.openDrawer)(); // JavaScriptスレッドでの処理に切り替え
  }
});

worklet を使う際の注意点

  • UI スレッドで実行される: worklet 内のコードは UI スレッドで実行されるため、パフォーマンス向上に繋がりますが、非同期処理や重い計算を避けるようにしましょう。
  • アニメーションやジェスチャーに特化: worklet は主にアニメーションやジェスチャー処理に使用され、通常の JavaScript ロジックには使用しません。

まとめ

  • worklet は UI スレッドで動作する関数を定義するために使用します。
  • runOnJS は UI スレッドから JavaScript スレッドの関数を呼び出すための方法です。
  • ジェスチャーやアニメーション処理を行う際には、workletrunOnJS を適切に使い分けることが重要です。

Reanimated 2 を活用することで、React Native アプリのパフォーマンスを大幅に向上させることができますが、適切な使い方を理解することが必要です。

);

コメント(0件)


トピックス