Text#onResponderGrant

2025-06-06

onResponderGrant は、React NativeのGesture Responder System(ジェスチャーレスポンダーシステム)の一部として提供されるイベントハンドラです。これは、ユーザーが画面に触れて、そのTextコンポーネントがそのタッチイベントの「レスポンダー」として承認されたときに発火します。

簡単に言うと、以下の流れの中で onResponderGrant が呼ばれます。

  1. ユーザーが画面に触れる (タッチ開始): ユーザーが Text コンポーネントが配置されている領域をタップしたり、長押ししたりといったアクションを開始します。

  2. レスポンダーになるための交渉: React Nativeのジェスチャーレスポンダーシステムは、タッチイベントが発生した際、どのコンポーネントがそのイベントを処理すべきかを決定します。この「どのコンポーネントがレスポンダーになるべきか?」という交渉が行われます。 Text コンポーネントがレスポンダーになることを希望する場合、通常は onStartShouldSetResponder または onMoveShouldSetResponder といったプロパティで true を返しておく必要があります。(Text はデフォルトでいくつかのタッチ処理に対応しているので、onPress などを使っていれば内部的にこれらの交渉を行っています。)

  3. onResponderGrant の発火: もし Text コンポーネントがタッチイベントのレスポンダーとして承認された場合、onResponderGrant イベントハンドラが発火します。

onResponderGrant が発火するタイミングと用途

onResponderGrant は、ジェスチャーが「開始された」ことを示すものです。具体的には、以下のような目的で利用されます。

  • イベント処理の開始: タッチイベントの処理を開始する準備を整えます。例えば、タイマーを開始したり、関連する他の状態を更新したりする場合などです。
  • ジェスチャーの状態の初期化: ドラッグやスワイプなどの複雑なジェスチャーを処理する場合、onResponderGrant でジェスチャーの開始位置や初期状態を記録・初期化することができます。PanResponder のように、より高度なジェスチャーを扱う際に内部的に利用されています。
  • 視覚的なフィードバックの提供: ユーザーがコンポーネントに触れた際に、それがインタラクティブであることを示すために、コンポーネントの見た目を変更する(例:背景色を変える、影をつけるなど)のに適しています。

Text コンポーネントには onPress というプロパティもありますが、これと onResponderGrant は異なります。

  • onResponderGrant: 「タッチが開始され、そのコンポーネントがイベントの責任を持つことになった」ときに発火します。指が離される前でも発火します。ドラッグや長押しなど、より複雑なジェスチャーの初期フェーズを捉えるのに使われます。

  • onPress: 「タップが完了した」ときに発火します。つまり、ユーザーが指を押し下げてから、同じコンポーネント上で指を離したときに発火します。一般的なボタンクリックのようなイベントを処理する際に使われます。



onResponderGrant が全く発火しない

共通の原因

  • Text コンポーネントのスタイルや内容の問題: Text コンポーネントが視覚的に表示されていなかったり、内容が空だったりすると、タッチ可能な領域が存在しないため、イベントが発火しません。
  • 他のコンポーネントがレスポンダーを奪っている: 親要素や兄弟要素に、より優先度の高いジェスチャーハンドラ(例: ScrollViewPanResponder を使用した複雑なジェスチャーコンポーネントなど)が存在する場合、それらがタッチイベントを「奪って」しまい、Text コンポーネントまでイベントが到達しないことがあります。
  • レスポンダーになるための交渉が不十分: onResponderGrant は、そのコンポーネントがタッチイベントのレスポンダーとして承認された場合にのみ発火します。Text コンポーネント自体はデフォルトで一部のレスポンダー機能を持っていますが、親コンポーネントがタッチを横取りしていたり、あるいは Text のタッチ領域が小さすぎたりすると、レスポンダーになる交渉が失敗することがあります。

トラブルシューティング

  • console.log を多用する: ジェスチャーレスポンダーシステムの各段階(onStartShouldSetResponderonMoveShouldSetResponderonResponderGrantonResponderMove など)で console.log を仕込み、どのイベントが発火しているか、どのイベントが発火していないかを詳細に追跡します。
  • タッチ領域の拡大: Text コンポーネントに paddingminHeight/minWidth を適用して、タッチ可能な領域を明確にします。これにより、実際にユーザーが意図した場所を触っているのにイベントが発火しないという問題を排除できます。
  • 親コンポーネントのジェスチャーハンドラの確認: 親コンポーネントが onStartShouldSetResponderonResponderGrant を持っている場合、それらのロジックを確認し、Text コンポーネントにイベントが伝播するように調整します。onResponderTerminationRequestonResponderTerminate といったプロパティが関係することもあります。
  • onStartShouldSetResponder の確認: Text コンポーネントに直接 onStartShouldSetResponder={() => true} を追加してみて、それでも発火しないか確認します。これにより、レスポンダーの交渉が問題かどうかを切り分けることができます。(ただし、通常 Text にはこれを明示的に書く必要はありません。あくまでデバッグ用です。)
    <Text
      onStartShouldSetResponder={() => true} // デバッグ用
      onResponderGrant={() => console.log('Text onResponderGrant 発火!')}
      style={{ padding: 20, borderWidth: 1, borderColor: 'red' }} // タッチ領域を視覚化
    >
      タップ可能なテキスト
    </Text>
    

onResponderGrant の後に他のイベントが発火しない/期待通りに動作しない

  • ジェスチャー終了時の処理漏れ: onResponderTerminate は、他のコンポーネントがレスポンダーを要求し、このコンポーネントがレスポンダー権限を失った場合に発火します。このイベントの処理が不足していると、予期せぬ状態になることがあります。
  • onResponderReleaseonResponderMove が連動していない: onResponderGrant が発火した後、ユーザーの指が動いたり離れたりしたときに、関連する onResponderMoveonResponderReleaseonResponderTerminate などのイベントが正しく設定されていないか、期待通りのロジックになっていない場合があります。
  • 全てのレスポンダーイベントを設定する: onResponderGrant を使用する場合、onResponderMoveonResponderReleaseonResponderTerminateRequestonResponderTerminate など、関連する他のイベントもすべて設定し、それぞれのコールバック内でログを出すなどして動作を確認します。
    <Text
      onStartShouldSetResponder={() => true}
      onResponderGrant={(event) => console.log('Grant', event.nativeEvent)}
      onResponderMove={(event) => console.log('Move', event.nativeEvent)}
      onResponderRelease={(event) => console.log('Release', event.nativeEvent)}
      onResponderTerminationRequest={() => {
        console.log('Termination Request');
        return true; // または false, 他のコンポーネントにレスポンダーを渡すか否か
      }}
      onResponderTerminate={() => console.log('Terminate')}
      style={{ padding: 50, backgroundColor: 'lightblue' }}
    >
      ジェスチャーテスト
    </Text>
    

イベントオブジェクト(nativeEvent)のプロパティが不正、または存在しない

  • 古いReact Nativeバージョン: 非常に古いReact Nativeのバージョンを使用している場合、一部の nativeEvent プロパティが現在のドキュメントと異なる可能性があります。
  • イベントの型誤解: onResponderGrant に渡されるイベントオブジェクトの構造を誤解している場合があります。
  • console.log(event.nativeEvent): 不明な場合は、シンプルに console.log(event.nativeEvent) を実行して、実際にどのようなプロパティが利用可能かを確認するのが最も確実です。
  • ドキュメントの確認: 最新のReact Nativeドキュメントで、onResponderGrant イベントの nativeEvent オブジェクトに含まれるプロパティを確認します。

onResponderGrant が高速な連続タップで複数回発火してしまう

  • onResponderGrant はタップが開始された時点、つまり指が画面に触れた時点で発火するため、非常に素早く連続してタップすると、それぞれのタッチに対して発火します。onPress とは異なり、「タップ完了」を待たないためです。
  • onPress の使用を検討: もし「タップが完了した」というイベントを処理したいのであれば、onResponderGrant ではなく onPress を使うべきです。onResponderGrant はジェスチャーの開始を捉えるためのものであり、単一のクリックイベントを処理するのには向いていません。
  • デバウンス/スロットリングの実装: 特定の処理を onResponderGrant の中で行う場合、lodashの debouncethrottle のような関数を使用して、短時間での連続発火を抑制します。
  • Stack OverflowやGitHub Issuesの検索: 多くの一般的な問題は、すでに他の開発者によって議論されている可能性があります。エラーメッセージや関連するキーワードで検索してみるのが有効です。
  • 最小限のコードで再現: 問題が発生した場合、可能な限り影響範囲を絞り込み、最小限のコードでその問題を再現できるかどうかを試します。これにより、どこに原因があるのかを特定しやすくなります。
  • 環境の確認: 使用しているReact Nativeのバージョン、Node.jsのバージョン、npm/Yarnのバージョンなどが、プロジェクトの要件や公式ドキュメントと一致しているか確認します。
  • React Native Debuggerの活用: React Native Debugger (Flipper) を使用すると、コンポーネントツリーの検査、ネットワークリクエストの監視、そして特に console.log の出力が整理されて表示されるため、デバッグ作業が格段に楽になります。


以下に、いくつかの具体的な例を示します。

タッチ開始時に背景色を変えるシンプルな例

この例では、Text コンポーネントがタッチされた瞬間に背景色を変化させ、指を離すと元に戻るようにします。

import React, { useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';

const ResponderText = () => {
  const [isPressed, setIsPressed] = useState(false);

  return (
    <View style={styles.container}>
      <Text
        style={[
          styles.text,
          { backgroundColor: isPressed ? '#ADD8E6' : '#F0F8FF' }, // 押されているかで色を変化
        ]}
        // onStartShouldSetResponder は、このコンポーネントがレスポンダーになることを希望するかを尋ねる
        // Textは通常デフォルトでtrueを返すため、明示的に記述する必要はないことが多い
        // onStartShouldSetResponder={() => true} 

        // onResponderGrant: タッチが開始され、このコンポーネントがレスポンダーに承認された時
        onResponderGrant={() => {
          console.log('onResponderGrant: テキストが触られました!');
          setIsPressed(true);
        }}
        // onResponderRelease: タッチが終了し、指が離された時
        onResponderRelease={() => {
          console.log('onResponderRelease: 指が離されました。');
          setIsPressed(false);
        }}
      >
        このテキストをタップしてください
      </Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 20,
    padding: 20,
    borderWidth: 1,
    borderColor: '#000',
    borderRadius: 10,
    textAlign: 'center',
  },
});

export default ResponderText;

解説

  • console.log を使って、各イベントがいつ発火するかを確認できます。
  • onResponderRelease が発火したときに isPressedfalse に設定し、背景色を元の色に戻します。
  • onResponderGrant が発火したときに isPressedtrue に設定し、背景色を水色に変えます。
  • useState を使って isPressed という状態を管理します。

長押しを検知する(簡単な実装)

onResponderGrant の後に、一定時間 onResponderMove が発火しなかった場合を長押しとみなす簡単な例です。

import React, { useState, useRef } from 'react';
import { StyleSheet, Text, View, Alert } from 'react-native';

const LongPressText = () => {
  const [message, setMessage] = useState('長押ししてください');
  const longPressTimer = useRef(null);
  const pressStartTime = useRef(0);

  const handleResponderGrant = () => {
    console.log('onResponderGrant: プレス開始');
    setMessage('長押し中...');
    pressStartTime.current = Date.now();

    // 500ms 後に長押しと判断
    longPressTimer.current = setTimeout(() => {
      const elapsedTime = Date.now() - pressStartTime.current;
      if (elapsedTime >= 500) { // タイマーがクリアされずに500ms経過したことを確認
        Alert.alert('長押し検出!', 'テキストが長押しされました。');
        setMessage('長押しされました!');
      }
    }, 500); // 500ms (0.5秒) 後にチェック
  };

  const handleResponderRelease = () => {
    console.log('onResponderRelease: プレス終了');
    clearTimeout(longPressTimer.current); // タイマーをクリア
    setMessage('長押ししてください'); // リリースでメッセージをリセット
  };

  const handleResponderTerminate = () => {
    console.log('onResponderTerminate: レスポンダー権限喪失');
    clearTimeout(longPressTimer.current); // レスポンダー権限を失った場合もタイマーをクリア
    setMessage('長押ししてください');
  };

  return (
    <View style={styles.container}>
      <Text
        style={styles.text}
        onResponderGrant={handleResponderGrant}
        onResponderRelease={handleResponderRelease}
        onResponderTerminate={handleResponderTerminate} // 他の要素がレスポンダーを奪った時に発火
      >
        {message}
      </Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 20,
    padding: 30,
    borderWidth: 2,
    borderColor: 'purple',
    borderRadius: 15,
    textAlign: 'center',
  },
});

export default LongPressText;

解説

  • onResponderRelease (指を離した時) や onResponderTerminate (他のコンポーネントがレスポンダー権限を奪った時) で、タイマーをクリアします。これにより、単なるタップやドラッグ開始時に誤って長押しが検知されるのを防ぎます。
  • onResponderGrant でタイマーをセットし、500ミリ秒後にアラートを表示するようにします。
  • longPressTimerpressStartTimeuseRef で保持し、コンポーネントが再レンダリングされても値が保持されるようにします。

タッチ座標の取得

onResponderGrant イベントオブジェクトからタッチの初期座標を取得する例です。

import React, { useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';

const TouchCoordinateText = () => {
  const [touchInfo, setTouchInfo] = useState({
    status: 'タップして開始',
    locationX: 0,
    locationY: 0,
    pageX: 0,
    pageY: 0,
  });

  const handleResponderGrant = (event) => {
    const { locationX, locationY, pageX, pageY } = event.nativeEvent;
    setTouchInfo({
      status: 'タッチされました!',
      locationX,
      locationY,
      pageX,
      pageY,
    });
    console.log('onResponderGrant event.nativeEvent:', event.nativeEvent);
  };

  const handleResponderRelease = () => {
    setTouchInfo((prev) => ({ ...prev, status: '指が離されました。' }));
  };

  return (
    <View style={styles.container}>
      <Text
        style={styles.text}
        onResponderGrant={handleResponderGrant}
        onResponderRelease={handleResponderRelease}
      >
        {touchInfo.status}
        {'\n'}
        {`要素内X: ${touchInfo.locationX.toFixed(2)}`}
        {'\n'}
        {`要素内Y: ${touchInfo.locationY.toFixed(2)}`}
        {'\n'}
        {`画面全体X: ${touchInfo.pageX.toFixed(2)}`}
        {'\n'}
        {`画面全体Y: ${touchInfo.pageY.toFixed(2)}`}
      </Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 18,
    padding: 40,
    borderWidth: 2,
    borderColor: 'green',
    borderRadius: 20,
    textAlign: 'center',
  },
});

export default TouchCoordinateText;
  • これらの情報を使って、タッチがどの位置で開始されたかを正確に把握できます。
  • event.nativeEvent には、タッチに関する低レベルの情報が含まれています。
    • locationX, locationY: イベントを受け取った要素の左上を原点とする相対座標。
    • pageX, pageY: スクリーン全体の左上を原点とする絶対座標。
  • onResponderGrant のコールバック関数は event オブジェクトを受け取ります。
  • 子要素との競合: Text コンポーネントがネストされた他のコンポーネントを含んでいる場合、子要素のジェスチャーハンドラと競合する可能性があります。その場合、onStartShouldSetResponderCapture などのキャプチャフェーズのイベントを検討する必要があるかもしれません。
  • レスポンダーシステムの理解: onResponderGrant はジェスチャーレスポンダーシステムの一部です。このシステムがどのように動作し、他の onStartShouldSetResponderonMoveShouldSetResponderonResponderMoveonResponderReleaseonResponderTerminate などのイベントとどのように連携するかを理解することが重要です。
  • onPress との使い分け: 単にタップを検出したい場合は onPress を使った方がシンプルです。onResponderGrant は、ジェスチャーの開始段階を捉えたい場合や、より複雑なジェスチャー(ドラッグ、スワイプ、長押しなど)を自作する場合に検討します。


主な代替手段は以下の通りです。

onPress / onLongPress / onPressIn / onPressOut

Text コンポーネントが提供するこれらのプロパティは、最も一般的で直感的なタッチイベントハンドラです。onResponderGrant よりも抽象化されており、特定のタッチジェスチャーの完了や開始・終了を簡単に扱えます。

  • onPressOut:

    • 説明: ユーザーがコンポーネントから指を離した瞬間に発火します。
    • ユースケース: onPressIn と組み合わせて、押下時の状態変更を元に戻す。
  • onPressIn:

    • 説明: ユーザーがコンポーネントを押し込んだ(触れた)瞬間に発火します。onResponderGrant と非常に似ていますが、より高レベルなイベントであり、ジェスチャーレスポンダーシステムの手動での交渉なしに利用できます。
    • onResponderGrant との違い: 多くのユースケースで onResponderGrant の直接的な代替として機能します。onPressInonResponderGrant の上に構築されているため、ジェスチャーシステムの詳細を気にせず使えます。
    • ユースケース: ボタンの押下時の視覚的なフィードバック(ハイライトなど)。
    • コード例:
      import React, { useState } from 'react';
      import { Text, StyleSheet, View } from 'react-native';
      
      const MyText = () => {
        const [isTouched, setIsTouched] = useState(false);
      
        return (
          <View style={styles.container}>
            <Text
              style={[
                styles.text,
                { backgroundColor: isTouched ? '#ADD8E6' : '#F0F8FF' },
              ]}
              onPressIn={() => {
                console.log('onPressIn: テキストが触られました!');
                setIsTouched(true);
              }}
              onPressOut={() => {
                console.log('onPressOut: 指が離されました。');
                setIsTouched(false);
              }}
            >
              このテキストを触ってください
            </Text>
          </View>
        );
      };
      
      const styles = StyleSheet.create({
        container: {
          flex: 1,
          justifyContent: 'center',
          alignItems: 'center',
        },
        text: {
          fontSize: 20,
          padding: 20,
          borderWidth: 1,
          borderColor: '#000',
          borderRadius: 10,
          textAlign: 'center',
        },
      });
      
      export default MyText;
      
  • onLongPress:

    • 説明: ユーザーがコンポーネントを一定時間(通常は0.5秒程度)長押ししたときに発火します。
    • onResponderGrant との違い: onResponderGrant は長押しの「開始」を検知しますが、onLongPress は長押しジェスチャーが「完了」したことを検知します。onResponderGrant を使って長押しを自作する場合よりもはるかに簡単です。
    • ユースケース: コンテキストメニューの表示、アイテムの選択モードへの切り替え。
    • コード例:
      import React from 'react';
      import { Text, StyleSheet, Alert } from 'react-native';
      
      const MyText = () => {
        return (
          <Text
            style={styles.text}
            onLongPress={() => Alert.alert('長押しされました!')}
          >
            長押ししてください
          </Text>
        );
      };
      
      const styles = StyleSheet.create({
        text: {
          fontSize: 20,
          padding: 20,
          borderWidth: 1,
          borderColor: 'green',
        },
      });
      
      export default MyText;
      
  • onPress:

    • 説明: ユーザーがコンポーネントをタップし、同じコンポーネント内で指を離したときに発火します。一般的なボタンクリックの動作です。
    • onResponderGrant との違い: onResponderGrant は指が触れた瞬間に発火しますが、onPress はタップが「完了」したときに発火します。
    • ユースケース: リンクのクリック、ボタンのタップ、簡単なインタラクション。
    • コード例:
      import React from 'react';
      import { Text, StyleSheet, Alert } from 'react-native';
      
      const MyText = () => {
        return (
          <Text
            style={styles.text}
            onPress={() => Alert.alert('タップされました!')}
          >
            タップ可能なテキスト
          </Text>
        );
      };
      
      const styles = StyleSheet.create({
        text: {
          fontSize: 20,
          padding: 20,
          borderWidth: 1,
          borderColor: 'blue',
        },
      });
      
      export default MyText;
      

Pressable コンポーネント

React Native 0.63から導入された Pressable は、すべてのインタラクションを統一的に処理するための推奨される方法です。TextonPress 系のプロパティよりも詳細な状態(pressed)を提供し、より高度なカスタマイズが可能です。

  • コード例:
    import React from 'react';
    import { Pressable, Text, StyleSheet } from 'react-native';
    
    const MyPressableText = () => {
      return (
        <Pressable
          onPressIn={() => console.log('Pressable: 触られました!')}
          onPressOut={() => console.log('Pressable: 指が離されました。')}
          onLongPress={() => console.log('Pressable: 長押しされました!')}
          // `pressed` プロパティを使ってスタイルを動的に変更
          style={({ pressed }) => [
            styles.pressableContainer,
            { backgroundColor: pressed ? '#FFDDC1' : '#FFFACD' },
          ]}
        >
          {({ pressed }) => (
            <Text style={styles.pressableText}>
              {pressed ? '押されています!' : '私を押してください'}
            </Text>
          )}
        </Pressable>
      );
    };
    
    const styles = StyleSheet.create({
      pressableContainer: {
        padding: 30,
        borderWidth: 1,
        borderColor: 'orange',
        borderRadius: 15,
      },
      pressableText: {
        fontSize: 22,
        textAlign: 'center',
        color: '#333',
      },
    });
    
    export default MyPressableText;
    
  • ユースケース: カスタムボタン、インタラクティブなリストアイテムなど、複雑なタッチインタラクションを持つUIコンポーネント。
  • onResponderGrant との違い: Pressable は、内部的にジェスチャーレスポンダーシステムを管理しており、開発者が直接 onResponderGrant を扱う必要がありません。より宣言的にインタラクションを定義できます。
  • 説明: タッチフィードバックを簡単に提供でき、タップ、長押し、ホバー、フォーカスなどの状態に基づいてUIを変化させることができます。onPressInonPressOut と同様のイベントを提供し、さらに pressed というプロパティを使用してスタイルの動的な変更が容易です。

PanResponder

  • コード例 (概念のみ、完全なドラッグ機能にはもっとコードが必要):
    import React, { useRef } from 'react';
    import { View, Text, StyleSheet, PanResponder } from 'react-native';
    
    const DraggableText = () => {
      const panResponder = useRef(
        PanResponder.create({
          // この要素がタッチに応答すべきかを尋ねる
          onStartShouldSetPanResponder: () => true,
          // レスポンダーになった瞬間 (onResponderGrant に相当)
          onPanResponderGrant: (evt, gestureState) => {
            console.log('PanResponder: ジェスチャー開始!');
            // ここで初期位置などを記録し、ドラッグの準備をする
          },
          // 指が動いた時 (onResponderMove に相当)
          onPanResponderMove: (evt, gestureState) => {
            // ここで要素の位置を更新する
            // console.log('PanResponder: 移動中', gestureState.dx, gestureState.dy);
          },
          // 指が離れた時 (onResponderRelease に相当)
          onPanResponderRelease: (evt, gestureState) => {
            console.log('PanResponder: ジェスチャー終了!');
            // ここでドラッグ終了後の処理を行う
          },
          // 他のコンポーネントがレスポンダーを要求した時に許可するか否か
          onPanResponderTerminateRequest: () => true,
          // レスポンダー権限を失った時 (onResponderTerminate に相当)
          onPanResponderTerminate: () => {
            console.log('PanResponder: レスポンダー権限喪失');
          },
        })
      ).current;
    
      return (
        <View style={styles.container}>
          <Text
            style={styles.text}
            {...panResponder.panHandlers} // PanResponderのハンドラをTextに適用
          >
            私をドラッグしてください
          </Text>
        </View>
      );
    };
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
      },
      text: {
        fontSize: 20,
        padding: 50,
        backgroundColor: 'lightgray',
        borderWidth: 1,
        borderColor: 'gray',
        borderRadius: 10,
        textAlign: 'center',
      },
    });
    
    export default DraggableText;
    
  • ユースケース: スライド可能な要素、ドラッグ&ドロップ機能、カスタムジェスチャーの認識。
  • onResponderGrant との違い: PanResponderonResponderGrant の機能を内包しており、さらに onResponderMoveonResponderRelease といった後続のイベントとの連携を容易にします。onResponderGrant を単体で使うよりも、ジェスチャーの状態管理が格段に楽になります。
  • 説明: ジェスチャーレスポンダーシステムへの生のアクセスを提供し、タッチイベントのライフサイクル全体を詳細に制御できます。onResponderGrantonResponderMoveonResponderRelease などのハンドラを一元的に管理し、複雑なジェスチャーを構築するために使用します。
  • ドラッグ、スワイプ、ピンチなどの複雑なジェスチャー: PanResponder を使用します。これは最も低レベルで強力なツールですが、その分コード量も多くなります。
  • タッチの開始・終了時の視覚的フィードバック: onPressIn, onPressOut、または Pressablepressed プロパティを使用します。Pressable の方がよりモダンで柔軟性が高いです。
  • 単純なタップや長押し: onPress, onLongPress が最も簡単で適切です。