Eventos de puntero en React Native
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Hoy compartimos una API experimental de puntero multiplataforma para React Native. Explicaremos las motivaciones, su funcionamiento y beneficios para los usuarios de React Native. Incluimos instrucciones para habilitarla y estamos entusiasmados por recibir sus comentarios.
Ha pasado más de un año desde que compartimos nuestra visión multiplataforma sobre las ventajas de construir más allá de móviles y cómo establece un estándar más alto para todas las plataformas. Durante este tiempo, incrementamos nuestras inversiones en React Native para VR, Escritorio y Web. Con las diferencias de hardware e interacciones en estas plataformas, surgió la pregunta de cómo React Native debería manejar la entrada de datos de manera integral.
Más allá del tacto
Históricamente, Escritorio y VR dependían de entrada por ratón y teclado, mientras móviles usaban principalmente tacto. Esta narrativa evolucionó con laptops táctiles y crecientes necesidades de soportar interacciones mediante teclado y lápiz en móviles. Todo esto el sistema de eventos táctiles de React Native no está equipado para manejar.
Como resultado, usuarios de plataformas fuera del árbol principal bifurcan React Native y/o crean componentes y módulos nativos personalizados para soportar características críticas como detección de hover o clic izquierdo. Esta divergencia genera redundancia de props con manejadores de eventos que sirven propósitos similares pero para diferentes plataformas. Añade complejidad al framework y dificulta compartir código entre plataformas. Por estas razones, el equipo se motivó a proporcionar una API de puntero multiplataforma.
React Native busca proporcionar APIs robustas y expresivas para construir en múltiples plataformas manteniendo experiencias características de cada plataforma. Diseñar tal API es desafiante, pero afortunadamente existe arte previo en el espacio de punteros que React Native puede aprovechar.
Mirando a la Web
La Web es una plataforma con desafíos similares al escalar a múltiples plataformas mientras considera diseños a prueba de futuro. El consorcio World Wide Web (W3C) tiene la tarea de establecer estándares y propuestas para construir una Web interoperable entre diferentes plataformas y navegadores.
Más relevante para nuestras necesidades, el W3C ha definido comportamientos para una forma abstracta de entrada llamada puntero. La especificación de Eventos de puntero se basa en eventos de ratón y busca proporcionar un único conjunto de eventos e interfaces para entrada de puntero multiplataforma, permitiendo aún manejo específico por dispositivo cuando sea necesario.
Seguir la especificación de Eventos de puntero proporciona muchos beneficios a los usuarios de React Native. Además de abordar los problemas mencionados, eleva las capacidades de plataformas que históricamente no consideraban interacciones multi-tipo. Piense en conectar un ratón Bluetooth a su teléfono Android o el Apple Pencil soportando hover en iPad M2.
Ser compatible con la especificación también brinda oportunidades para compartir conocimiento entre Web y React Native. La educación sobre expectativas Web respecto a Eventos de puntero puede servir doblemente a desarrolladores de React Native. Sin embargo, también reconocemos que los requisitos de React Native difieren de la web, y nuestro enfoque hacia especificaciones es de mejor esfuerzo con desviaciones bien documentadas para claridad. Existe trabajo relacionado en alinear ciertos estándares Web para reducir fragmentación de APIs en accesibilidad y rendimiento.
Portando pruebas de plataforma web
Aunque la especificación de Eventos de puntero proporciona interfaces y descripciones de comportamiento, encontramos que no era lo suficientemente específica para hacer cambios confiables usando la especificación como verificación. Sin embargo, los navegadores web usan otro mecanismo para asegurar cumplimiento e interoperabilidad: ¡las Pruebas de plataforma web!
Las Pruebas de plataforma web están escritas para funcionar contra las APIs imperativas DOM del navegador, no soportadas por React Native al usar sus propias primitivas de vista. Esto significa que no podemos compartir código de pruebas con navegadores y en su lugar tenemos una API de pruebas análoga para React Native que facilita portar esas Pruebas de plataforma web.
Implementamos un nuevo marco de pruebas manuales que ahora usamos para verificar nuestras implementaciones mediante RNTester. Estas pruebas se denominan tentativamente Pruebas de plataforma RNTester y aún son bastante básicas. Nuestra implementación proporciona una API para construir casos de prueba como componentes que se renderizan y donde los resultados se reportan únicamente mediante la UI.

Estas pruebas seguirán siendo útiles a medida que avancemos en la completitud de nuestra implementación de Pointer Events. También escalarán para probar implementaciones de Pointer Events en plataformas más allá de Android e iOS. A medida que aumente el número de pruebas en nuestro conjunto, buscaremos automatizar su ejecución para detectar mejor regresiones en nuestras implementaciones.
Cómo funciona
Gran parte de nuestra implementación de Pointer Events se basa en infraestructura existente para despachar eventos táctiles. En Android e iOS aprovechamos los eventos MotionEvent y UITouch respectivamente. El flujo general de despacho de eventos se ilustra a continuación.

Usando Android como ejemplo, el enfoque general para aprovechar eventos de plataforma es:
-
Iterar todos los punteros del
MotionEventy realizar búsqueda en profundidad para determinar la vista React objetivo de cada puntero y su ruta ancestral. -
Mapear la categoría de
MotionEventa eventos de puntero relevantes. Existe relación 1-a-muchos entreMotionEventyPointerEvent. En la ilustración, las líneas punteadas indican eventos disparados si el dispositivo no admite hover.

-
Construir la interfaz
PointerEventcon detalles de plataforma delMotionEventy estado caché de interacciones previas. (Ej. propiedadbutton) -
Despachar eventos de puntero desde Android a la cola de eventos principal de React Native, usando JSI para llamar al método
dispatchEventenreact-native-rendererque itera el árbol React para las fases bubble y capture.
Progreso de implementación
En cuanto a nuestro progreso actual implementando la especificación Pointer Events, nos hemos centrado en una implementación base sólida de eventos más comunes para manejar pulsaciones, hover y movimiento.
Eventos
| Implemented | Work in Progress | Yet to be Implemented |
|---|---|---|
| onPointerOver | onPointerCancel | onClick |
| onPointerEnter | onContextMenu | |
| onPointerDown | onGotPointerCapture | |
| onPointerMove | onLostPointerCapture | |
| onPointerUp | onPointerRawUpdate | |
| onPointerOut | ||
| onPointerLeave |
onPointerCancel está conectado al evento "cancel" nativo, pero esto no necesariamente corresponde a cuándo la plataforma web espera que se dispare.
Propiedades de eventos
Para cada evento mencionado, también implementamos la mayoría de propiedades esperadas en el objeto PointerEvent (expuestas en React Native mediante event.nativeEvent). Puedes encontrar todas las propiedades implementadas en la definición de interfaz Flowtype. Una excepción notable es la propiedad relatedTarget, ya que exponer referencias nativas de vista de esta manera ad-hoc no es trivial.
Trabajo futuro y exploración
Además de los eventos mencionados, existen otras API relacionadas con los Eventos de Puntero. En el futuro, planeamos implementar estas API como parte de este esfuerzo. Estas incluyen:
-
API de Captura de Puntero
- Incluye la API imperativa expuesta en referencias de elementos:
setPointerCapture(),releasePointerCapture()yhasPointerCapture().
- Incluye la API imperativa expuesta en referencias de elementos:
-
Propiedad de estilo
touch-action- La web usa esta propiedad CSS para negociar gestos declarativamente entre el navegador y el código de manejo de eventos de un sitio. En React Native podría usarse para negociar el manejo de eventos entre los controladores de eventos de puntero de una View y un ScrollView padre.
-
click,contextmenu,auxclickclickes una definición abstracta de interacción que puede activarse mediante paradigmas de accesibilidad u otras interacciones características de la plataforma.
Otro beneficio de la implementación nativa de Eventos de Puntero es que nos permitirá revisar y mejorar varias formas de manejo de gestos actualmente limitadas solo a eventos táctiles y manejadas en JavaScript por las API de Responder, Pressability y PanResponder.
Además, seguimos explorando la inclusión de una implementación de la interfaz EventTarget para componentes host de React Native (ej. add/removeEventListener), lo que creemos permitirá más abstracciones en el código de usuario para manejar interacciones de puntero.
Pruébalo
Nuestra implementación de Eventos de Puntero sigue siendo experimental, pero nos interesa recibir comentarios de la comunidad sobre lo compartido. Si deseas probar esta API, deberás habilitar algunas banderas de características:
Habilitar banderas de características
Anular las banderas de características nativas a continuación (como RCTConstants y ReactFeatureFlags) implica técnicamente acceder a los componentes internos de React Native. Hacerlo podría dañar tu configuración pronto, ya que estamos trabajando para eliminarlas gradualmente con el fin de implementar Pointer Events de manera más amplia.
Los Eventos de Puntero solo están implementados para la Nueva Arquitectura (Fabric) y están disponibles únicamente en React Native 0.71+, que al momento de escribir es una versión candidata.
En tu archivo JavaScript de entrada (index.js en la plantilla predeterminada de React Native) deberás habilitar la bandera shouldEmitW3CPointerEvents para Eventos de Puntero y shouldPressibilityUseW3CPointerEventsForHover para usar Eventos de Puntero en Pressability.
import ReactNativeFeatureFlags from 'react-native/Libraries/ReactNative/ReactNativeFeatureFlags';
// enable the JS-side of the w3c PointerEvent implementation
ReactNativeFeatureFlags.shouldEmitW3CPointerEvents = () => true;
// enable hover events in Pressibility to be backed by the PointerEvent implementation
ReactNativeFeatureFlags.shouldPressibilityUseW3CPointerEventsForHover =
() => true;
Específico para iOS
Para garantizar que los eventos de puntero se envíen desde el renderizador nativo de iOS, deberás activar una bandera nativa en el código de inicialización de tu aplicación nativa (típicamente AppDelegate.mm).
#import <React/RCTConstants.h>
// ...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTSetDispatchW3CPointerEvents(YES);
// ...
}
Nota: Para que la implementación de Eventos de Puntero pueda distinguir entre punteros de mouse y táctiles en iOS, debes agregar UIApplicationSupportsIndirectInputEvents al info.plist de tu proyecto en Xcode.
Específico para Android
Similar a iOS, Android tiene una bandera de característica que deberás habilitar en la inicialización de tu aplicación, típicamente en tu onCreate para la actividad o superficie raíz de React.
import com.facebook.react.config.ReactFeatureFlags;
//... somewhere in initialization
@Override
public void onCreate() {
ReactFeatureFlags.dispatchPointerEvents = true;
}
JavaScript
function onPointerOver(event) {
console.log(
'Over blue box offset: ',
event.nativeEvent.offsetX,
event.nativeEvent.offsetY,
);
}
// ... in some component
<View
onPointerOver={onPointerOver}
style={{height: 100, width: 100, backgroundColor: 'blue'}}
/>;
Tus comentarios son bienvenidos
Actualmente, los Eventos de Puntero son utilizados por nuestra plataforma VR y potencian Oculus Store, pero también buscamos comentarios tempranos de la comunidad sobre nuestro enfoque e implementación actual. Estamos emocionados de compartir más avances y si tienes preguntas o ideas sobre este trabajo, únete a la discusión dedicada sobre Eventos de Puntero.

