Saltar al contenido principal

Usar TypeScript con React Native

· 8 min de lectura
Ash Furrow
Ingeniero de Software en Artsy
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

¡JavaScript! Todos lo amamos. Pero algunos también adoramos los tipos de datos. Afortunadamente, existen opciones para añadir tipos más fuertes a JavaScript. Mi favorito es TypeScript, aunque React Native incluye soporte para Flow de forma nativa. Tu preferencia dependerá de gustos personales, ya que cada uno tiene su propio enfoque para añadir la magia de los tipos a JavaScript. Hoy veremos cómo usar TypeScript en aplicaciones de React Native.

Esta publicación utiliza como guía el repositorio TypeScript-React-Native-Starter de Microsoft.

Actualización: Desde que se escribió esta entrada, el proceso se ha simplificado aún más. Puedes reemplazar toda la configuración descrita en este post ejecutando un solo comando:

npx react-native init MyAwesomeProject --template react-native-template-typescript

Sin embargo, existen algunas limitaciones en el soporte de TypeScript en Babel, que el artículo anterior explica en detalle. Los pasos descritos en esta publicación siguen funcionando, y Artsy aún utiliza react-native-typescript-transformer en producción, pero la forma más rápida de comenzar con React Native y TypeScript es usando el comando anterior. Siempre puedes cambiar más adelante si es necesario.

En cualquier caso, ¡disfrútalo! La publicación original continúa a continuación.

Prerrequisitos

Dado que podrías estar desarrollando en varias plataformas diferentes dirigidas a distintos tipos de dispositivos, la configuración básica puede ser compleja. Primero debes asegurarte de poder ejecutar una aplicación React Native básica sin TypeScript. Sigue las instrucciones en el sitio web de React Native para comenzar. Cuando hayas logrado implementar en un dispositivo o emulador, estarás listo para iniciar una aplicación React Native con TypeScript.

También necesitarás Node.js, npm y Yarn.

Inicialización

Una vez que hayas probado a crear un proyecto ordinario de React Native, estarás listo para añadir TypeScript. Vamos a hacerlo.

react-native init MyAwesomeProject
cd MyAwesomeProject

Agregar TypeScript

El siguiente paso es añadir TypeScript a tu proyecto. Los siguientes comandos:

  • añadirán TypeScript a tu proyecto

  • agregarán React Native TypeScript Transformer a tu proyecto

  • inicializarán un archivo de configuración vacío de TypeScript, que configuraremos después

  • añadirán un archivo de configuración vacío para React Native TypeScript Transformer, que configuraremos a continuación

  • agregarán tipados para React y React Native

Bien, ejecutemos estos comandos.

yarn add --dev typescript
yarn add --dev react-native-typescript-transformer
yarn tsc --init --pretty --jsx react
touch rn-cli.config.js
yarn add --dev @types/react @types/react-native

El archivo tsconfig.json contiene todas las configuraciones del compilador de TypeScript. Los valores predeterminados creados por el comando anterior son adecuados en su mayoría, pero abre el archivo y descomenta la siguiente línea:

{
/* Search the config file for the following line and uncomment it. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
}

El archivo rn-cli.config.js contiene la configuración de React Native TypeScript Transformer. Ábrelo y añade lo siguiente:

module.exports = {
getTransformModulePath() {
return require.resolve('react-native-typescript-transformer');
},
getSourceExts() {
return ['ts', 'tsx'];
},
};

Migrar a TypeScript

Renombra los archivos generados App.js y __tests_/App.js como App.tsx. index.js debe mantener la extensión .js. Todos los archivos nuevos deben usar la extensión .tsx (o .ts si el archivo no contiene JSX).

Si intentaras ejecutar la aplicación ahora, obtendrías un error como object prototype may only be an object or null. Esto se debe a un fallo al importar la exportación predeterminada de React junto con una exportación nombrada en la misma línea. Abre App.tsx y modifica la importación al inicio del archivo:

-import React, { Component } from 'react';
+import React from 'react'
+import { Component } from 'react';

Parte de esto se relaciona con diferencias en cómo Babel y TypeScript interoperan con módulos CommonJS. En el futuro, ambos convergerán en el mismo comportamiento.

En este punto, deberías poder ejecutar la aplicación de React Native.

Configuración de pruebas con TypeScript

React Native incluye Jest por defecto. Para probar aplicaciones React Native con TypeScript, añadiremos ts-jest a nuestras devDependencies.

yarn add --dev ts-jest

Luego, abriremos nuestro package.json y reemplazaremos el campo jest con lo siguiente:

{
"jest": {
"preset": "react-native",
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"transform": {
"^.+\\.(js)$": "<rootDir>/node_modules/babel-jest",
"\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
"\\.snap$",
"<rootDir>/node_modules/"
],
"cacheDirectory": ".jest/cache"
}
}

Esto configurará Jest para ejecutar archivos .ts y .tsx con ts-jest.

Instalación de declaraciones de tipos para dependencias

Para obtener la mejor experiencia en TypeScript, necesitamos que el verificador de tipos comprenda la estructura y API de nuestras dependencias. Algunas bibliotecas publican paquetes con archivos .d.ts (archivos de declaración de tipos), que describen la estructura del JavaScript subyacente. Para otras bibliotecas, tendremos que instalar explícitamente el paquete correspondiente en el ámbito npm @types/.

Por ejemplo, aquí necesitaremos tipos para Jest, React, React Native y React Test Renderer.

yarn add --dev @types/jest @types/react @types/react-native @types/react-test-renderer

Guardamos estos paquetes de declaración de tipos como dependencias de desarrollo porque esta es una aplicación React Native que solo usa estas dependencias durante el desarrollo, no en tiempo de ejecución. Si estuviéramos publicando una biblioteca en NPM, podríamos tener que añadir algunas de estas dependencias de tipos como dependencias regulares.

Puedes leer más aquí sobre cómo obtener archivos .d.ts.

Ignorar más archivos

Para tu control de código fuente, querrás ignorar la carpeta .jest. Si usas git, podemos simplemente añadir entradas a nuestro archivo .gitignore.

# Jest
#
.jest/

Como punto de control, considera confirmar tus archivos en el sistema de control de versiones.

git init
git add .gitignore # import to do this first, to ignore our files
git add .
git commit -am "Initial commit."

Añadiendo un componente

Añadamos un componente a nuestra aplicación. Creemos un componente Hello.tsx. Es un componente pedagógico, no algo que escribirías realmente en una app, pero algo no trivial que muestra cómo usar TypeScript en React Native.

Crea un directorio components y añade el siguiente ejemplo.

// components/Hello.tsx
import React from 'react';
import {Button, StyleSheet, Text, View} from 'react-native';

export interface Props {
name: string;
enthusiasmLevel?: number;
}

interface State {
enthusiasmLevel: number;
}

export class Hello extends React.Component<Props, State> {
constructor(props: Props) {
super(props);

if ((props.enthusiasmLevel || 0) <= 0) {
throw new Error(
'You could be a little more enthusiastic. :D',
);
}

this.state = {
enthusiasmLevel: props.enthusiasmLevel || 1,
};
}

onIncrement = () =>
this.setState({
enthusiasmLevel: this.state.enthusiasmLevel + 1,
});
onDecrement = () =>
this.setState({
enthusiasmLevel: this.state.enthusiasmLevel - 1,
});
getExclamationMarks = (numChars: number) =>
Array(numChars + 1).join('!');

render() {
return (
<View style={styles.root}>
<Text style={styles.greeting}>
Hello{' '}
{this.props.name +
this.getExclamationMarks(this.state.enthusiasmLevel)}
</Text>

<View style={styles.buttons}>
<View style={styles.button}>
<Button
title="-"
onPress={this.onDecrement}
accessibilityLabel="decrement"
color="red"
/>
</View>

<View style={styles.button}>
<Button
title="+"
onPress={this.onIncrement}
accessibilityLabel="increment"
color="blue"
/>
</View>
</View>
</View>
);
}
}

// styles
const styles = StyleSheet.create({
root: {
alignItems: 'center',
alignSelf: 'center',
},
buttons: {
flexDirection: 'row',
minHeight: 70,
alignItems: 'stretch',
alignSelf: 'center',
borderWidth: 5,
},
button: {
flex: 1,
paddingVertical: 0,
},
greeting: {
color: '#999',
fontWeight: 'bold',
},
});

¡Vaya! Es mucho, pero analicémoslo:

  • En lugar de renderizar elementos HTML como div, span, h1, etc., renderizamos componentes como View y Button. Estos son componentes nativos que funcionan en diferentes plataformas.

  • Los estilos se especifican usando la función StyleSheet.create que nos proporciona React Native. Las hojas de estilo de React nos permiten controlar el diseño usando Flexbox y estilizar usando construcciones similares a CSS.

Añadiendo pruebas para el componente

Ahora que tenemos un componente, probémoslo.

Ya tenemos Jest instalado como ejecutor de pruebas. Escribiremos pruebas de snapshot para nuestros componentes. Añadamos el complemento necesario para estas pruebas:

yarn add --dev react-addons-test-utils

Ahora creemos una carpeta __tests__ dentro del directorio components y añadamos una prueba para Hello.tsx:

// components/__tests__/Hello.tsx
import React from 'react';
import renderer from 'react-test-renderer';

import {Hello} from '../Hello';

it('renders correctly with defaults', () => {
const button = renderer
.create(<Hello name="World" enthusiasmLevel={1} />)
.toJSON();
expect(button).toMatchSnapshot();
});

La primera vez que se ejecuta la prueba, creará una instantánea del componente renderizado y la almacenará en el archivo components/__tests__/__snapshots__/Hello.tsx.snap. Cuando modifiques tu componente, deberás actualizar las instantáneas y revisar los cambios inadvertidos. Puedes obtener más información sobre cómo probar componentes de React Native aquí.

Próximos pasos

Consulta el tutorial oficial de React y la biblioteca de gestión del estado Redux. Estos recursos pueden ser útiles al desarrollar aplicaciones con React Native. Además, quizás quieras explorar ReactXP, una biblioteca de componentes escrita completamente en TypeScript que soporta tanto React para web como React Native.

¡Disfruta de un entorno de desarrollo React Native más seguro con tipos!

Construida con React Native - La aplicación de Build.com

· 6 min de lectura
Garrett McCullough
Ingeniero Senior de Móviles
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Build.com, con sede en Chico, California, es uno de los minoristas en línea más grandes de artículos para mejoras del hogar. El equipo ha mantenido un sólido negocio centrado en la web durante 18 años y comenzó a considerar una aplicación móvil en 2015. Desarrollar aplicaciones nativas separadas para Android e iOS no era práctico debido a nuestro equipo reducido y experiencia limitada en desarrollo nativo. En su lugar, decidimos arriesgarnos con el entonces muy nuevo framework React Native. ¡Nuestro commit inicial fue el 12 de agosto de 2015 usando React Native v0.8.0! Lanzamos la aplicación en ambas tiendas de aplicaciones el 15 de octubre de 2016. Durante los últimos dos años, hemos seguido actualizando y expandiendo la aplicación. Actualmente estamos en la versión 0.53.0 de React Native.

Puedes ver la aplicación en https://www.build.com/app.

Características

Nuestra aplicación es completa e incluye todo lo que esperarías de una app de comercio electrónico: listados de productos, búsqueda y ordenación, capacidad para configurar productos complejos, favoritos, etc. Aceptamos métodos de pago estándar con tarjeta de crédito, así como PayPal y Apple Pay para nuestros usuarios de iOS.

Algunas características destacadas que quizás no esperes incluyen:

  1. Modelos 3D disponibles para alrededor de 40 productos con 90 acabados

  2. Realidad Aumentada (AR) para que el usuario pueda ver cómo se verán las luces y griferías en su hogar con una precisión de tamaño del 98%. ¡La aplicación Build.com con React Native está destacada en la Apple App Store en la categoría de compras con AR! ¡La AR ya está disponible para Android e iOS!

  3. Funciones de gestión colaborativa de proyectos que permiten crear listas de compras para las diferentes fases de un proyecto y colaborar en la selección

Estamos trabajando en muchas características nuevas y emocionantes que seguirán mejorando nuestra experiencia de aplicación, incluida la siguiente fase de Compras Inmersivas con AR.

Nuestro flujo de desarrollo

Build.com permite a cada desarrollador elegir las herramientas que mejor se adapten a ellos.

  • Los IDEs incluyen Atom, IntelliJ, VS Code, Sublime, Eclipse, etc.

  • Para las pruebas unitarias, los desarrolladores son responsables de crear tests unitarios de Jest para cualquier componente nuevo y estamos trabajando para aumentar la cobertura de las partes más antiguas de la aplicación usando jest-coverage-ratchet.

  • Usamos Jenkins para construir nuestras versiones beta y candidatas a lanzamiento. Este proceso funciona bien para nosotros, pero aún requiere trabajo significativo para crear las notas de la versión y otros artefactos.

  • Las pruebas de integración incluyen un grupo compartido de testers que trabajan en escritorio, móvil y web. Nuestro ingeniero de automatización está desarrollando nuestra suite de pruebas de integración automatizadas usando Java y Appium.

  • Otras partes del flujo de trabajo incluyen una configuración detallada de eslint, reglas personalizadas que refuerzan propiedades necesarias para pruebas, y hooks de pre-push que bloquean cambios problemáticos.

Bibliotecas utilizadas en la aplicación

La aplicación de Build.com depende de varias bibliotecas open source comunes, incluyendo: Redux, Moment, Numeral, Enzyme y numerosos módulos puente de React Native. También usamos varias bibliotecas open source bifurcadas; bifurcadas porque estaban abandonadas o porque necesitábamos características personalizadas. Un conteo rápido muestra alrededor de 115 dependencias de JavaScript y nativas. Nos gustaría explorar herramientas que eliminen bibliotecas no utilizadas.

Estamos en proceso de añadir tipado estático mediante TypeScript e investigando el optional chaining. Estas características podrían ayudarnos a resolver un par de tipos de errores que aún vemos:

  • Datos que son de un tipo incorrecto

  • Datos que son undefined porque un objeto no contenía lo que esperábamos

Contribuciones de código abierto

Dado que dependemos tanto del código abierto, nuestro equipo está comprometido a contribuir a la comunidad. Build.com permite que el equipo libere como open source las bibliotecas que hemos creado y nos anima a contribuir en las bibliotecas que utilizamos.

Hemos publicado y mantenido varias bibliotecas de React Native:

  • react-native-polyfill

  • react-native-simple-store

  • react-native-contact-picker

También hemos contribuido a una larga lista de bibliotecas incluyendo: React y React Native, react-native-schemes-manager, react-native-swipeable, react-native-gallery, react-native-view-transformer, react-native-navigation.

Nuestro recorrido

Hemos visto un gran crecimiento en React Native y su ecosistema en los últimos años. Al principio, parecía que cada versión de React Native arreglaba algunos errores pero introducía varios nuevos. Por ejemplo, la depuración remota de JS estuvo rota en Android durante varios meses. Afortunadamente, las cosas se volvieron mucho más estables en 2017.

Bibliotecas de navegación

Uno de nuestros grandes desafíos recurrentes han sido las bibliotecas de navegación. Durante mucho tiempo usamos la biblioteca ex-nav de Expo. Funcionaba bien para nosotros pero finalmente quedó obsoleta. Sin embargo, estábamos en pleno desarrollo de funciones en ese momento, así que tomarnos tiempo para cambiar la biblioteca de navegación no era factible. Eso significó que tuvimos que bifurcar la biblioteca y parchearla para admitir React 16 y el iPhone X. Finalmente, pudimos migrar a react-native-navigation y esperamos que siga recibiendo soporte.

Módulos de puente

Otro gran desafío han sido los módulos de puente. Cuando comenzamos, faltaban muchos puentes críticos. Uno de mis compañeros escribió react-native-contact-picker porque necesitábamos acceso al selector de contactos de Android en nuestra aplicación. También hemos visto muchos puentes que se rompieron con cambios en React Native. Por ejemplo, hubo un cambio importante en React Native v40 y cuando actualizamos nuestra aplicación, tuve que enviar PRs para arreglar 3 o 4 bibliotecas que aún no se habían actualizado.

Mirando hacia adelante

A medida que React Native sigue creciendo, nuestra lista de deseos para la comunidad incluye:

  • Estabilizar y mejorar las bibliotecas de navegación

  • Mantener el soporte para bibliotecas en el ecosistema de React Native

  • Mejorar la experiencia para añadir bibliotecas nativas y módulos de puente a un proyecto

Las empresas e individuos en la comunidad de React Native han sido excelentes al ofrecer su tiempo y esfuerzo para mejorar las herramientas que todos usamos. Si aún no te has involucrado en el código abierto, espero que consideres mejorar el código o la documentación de algunas bibliotecas que utilizas. Hay muchos artículos que te ayudarán a comenzar y puede ser mucho más fácil de lo que piensas.

Construyendo <InputAccessoryView> para React Native

· 7 min de lectura
Peter Argany
Ingeniero de Software en Facebook
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Motivación

Hace tres años, se abrió un issue en GitHub para solicitar compatibilidad con input accessory view en React Native.

Durante los años siguientes, hubo innumerables '+1', diversas soluciones alternativas y cero cambios concretos en RN sobre este tema, hasta hoy. Comenzando con iOS, exponemos una API para acceder a la vista de accesorios nativa y nos emociona compartir cómo la construimos.

Antecedentes

¿Qué es exactamente una input accessory view? Según la documentación para desarrolladores de Apple, es una vista personalizable que puede anclarse en la parte superior del teclado del sistema cuando un receptor se convierte en primer respondedor. Cualquier elemento que herede de UIResponder puede redeclarar la propiedad .inputAccessoryView como lectura-escritura y gestionar una vista personalizada aquí. La infraestructura de respondedores monta la vista y la mantiene sincronizada con el teclado del sistema. Los gestos que ocultan el teclado (como arrastrar o tocar) se aplican a la vista de accesorios a nivel de framework. Esto permite crear contenido con ocultamiento interactivo del teclado, una característica fundamental en aplicaciones de mensajería de primer nivel como iMessage y WhatsApp.

Existen dos casos de uso comunes para anclar una vista al teclado. El primero es crear una barra de herramientas, como el selector de fondos en el compositor de Facebook.

En este escenario, el teclado está enfocado en un campo de texto, y la vista de accesorios proporciona funcionalidad adicional contextual. En aplicaciones de mapas podría mostrar sugerencias de direcciones, mientras que en editores de texto podría incluir herramientas de formato avanzado.


El UIResponder de Objective-C que posee el <InputAccessoryView> en este caso es claro: el <TextInput> se convierte en primer respondedor, y en el código nativo esto se traduce en una instancia de UITextView o UITextField.

El segundo escenario común son entradas de texto persistentes:

Aquí, la entrada de texto forma parte de la propia vista de accesorios. Es común en aplicaciones de mensajería, donde puedes componer mensajes mientras navegas por un hilo de conversación.


¿Quién posee el <InputAccessoryView> aquí? ¿Puede ser nuevamente UITextView o UITextField? La entrada de texto está dentro de la vista de accesorios, lo que sugiere dependencia circular. Resolver esto merece su propia publicación. Spoiler: el propietario es una subclase genérica de UIView que invocamos manualmente con becomeFirstResponder.

Diseño de API

Ahora que sabemos qué es <InputAccessoryView> y cómo usarlo, el siguiente paso es diseñar una API coherente para ambos casos de uso, compatible con componentes existentes como <TextInput>.

Para barras de herramientas del teclado, debemos considerar:

  1. Poder integrar cualquier jerarquía de vistas de React Native en el <InputAccessoryView>.

  2. Que esta jerarquía de vistas genérica y desacoplada acepte interacciones táctiles y pueda manipular el estado de la aplicación.

  3. Vincular un <InputAccessoryView> a un <TextInput> específico.

  4. Compartir un <InputAccessoryView> entre múltiples entradas de texto sin duplicar código.

Podemos lograr el punto #1 usando un concepto similar a los portales de React. En este diseño, trasladamos las vistas de React Native a una jerarquía UIView gestionada por la infraestructura de respuesta. Dado que las vistas de React Native se renderizan como UIViews, esto es bastante directo: simplemente podemos sobrescribir:

- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex

y redirigir todas las subvistas a una nueva jerarquía UIView. Para el punto #2, configuramos un nuevo RCTTouchHandler para el <InputAccessoryView>. Las actualizaciones de estado se logran mediante callbacks de eventos regulares. Para los puntos #3 y #4, usamos el campo nativeID para localizar la jerarquía UIView de la vista accesoria en código nativo durante la creación de un componente <TextInput>. Esta función utiliza la propiedad .inputAccessoryView del campo de texto nativo subyacente. Esto enlaza efectivamente <InputAccessoryView> con <TextInput> en sus implementaciones de ObjC.

Soportar campos de texto persistentes (escenario 2) añade más restricciones. En este diseño, la vista accesoria tiene un campo de texto como hijo, por lo que vincular mediante nativeID no es viable. En su lugar, establecemos la propiedad .inputAccessoryView de una UIView genérica fuera de pantalla a nuestra jerarquía nativa <InputAccessoryView>. Al indicar manualmente a esta UIView genérica que se convierta en primera respondedora, la jerarquía se monta mediante la infraestructura de respuesta. Este concepto se explica detalladamente en la publicación de blog mencionada anteriormente.

Dificultades

Por supuesto, no todo fue sencillo al construir esta API. Estas son algunas dificultades que encontramos y cómo las solucionamos.

Una idea inicial para construir esta API implicaba escuchar a NSNotificationCenter los eventos UIKeyboardWill(Show/Hide/ChangeFrame). Este patrón se usa en bibliotecas de código abierto y en partes internas de la app de Facebook. Desafortunadamente, los eventos UIKeyboardDidChangeFrame no se activaban a tiempo para actualizar el marco de <InputAccessoryView> durante deslizamientos. Además, estos eventos no capturan cambios en la altura del teclado. Esto genera errores que se manifiestan así:

En iPhone X, los teclados de texto y emoji tienen alturas diferentes. Muchas apps que usan eventos de teclado para manipular campos de texto tuvieron que corregir este error. Nuestra solución fue comprometernos a usar la propiedad .inputAccessoryView, haciendo que la infraestructura de respuesta gestione estas actualizaciones de marco.


Otro error complejo fue evitar la barra de inicio en iPhone X. Podrías pensar: "¡Apple creó safeAreaLayoutGuide para esto, es trivial!". Fuimos igual de ingenuos. El primer problema es que la implementación nativa de <InputAccessoryView> no tiene ventana para anclarse hasta que está por aparecer. Podemos sobrescribir -(BOOL)becomeFirstResponder y aplicar restricciones de diseño allí. Al cumplir estas restricciones, la vista accesoria sube, pero aparece otro error:

La vista accesoria evita la barra de inicio, pero ahora se ve contenido tras el área insegura. La solución está en este radar. Envolví la jerarquía nativa de <InputAccessoryView> en un contenedor que no cumple las restricciones de safeAreaLayoutGuide. El contenedor nativo cubre el contenido del área insegura, mientras el <InputAccessoryView> permanece dentro de los límites seguros.


Ejemplo de Uso

Este ejemplo crea un botón en la barra de herramientas del teclado para resetear el estado de <TextInput>:

class TextInputAccessoryViewExample extends React.Component<
{},
*,
> {
constructor(props) {
super(props);
this.state = {text: 'Placeholder Text'};
}

render() {
const inputAccessoryViewID = 'inputAccessoryView1';
return (
<View>
<TextInput
style={styles.default}
inputAccessoryViewID={inputAccessoryViewID}
onChangeText={text => this.setState({text})}
value={this.state.text}
/>
<InputAccessoryView nativeID={inputAccessoryViewID}>
<View style={{backgroundColor: 'white'}}>
<Button
onPress={() =>
this.setState({text: 'Placeholder Text'})
}
title="Reset Text"
/>
</View>
</InputAccessoryView>
</View>
);
}
}

Otro ejemplo de Campos de Texto Persistentes está disponible en el repositorio.

¿Cuándo podré usar esto?

El commit completo para la implementación de esta característica está aquí. <InputAccessoryView> estará disponible en la próxima versión v0.55.0.

¡Feliz escritura con teclado :)

Uso de AWS con React Native

· 11 min de lectura
Richard Threlkeld
Gerente Senior de Producto Técnico en AWS Mobile
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

AWS es ampliamente reconocido en la industria tecnológica como proveedor de servicios en la nube. Estos incluyen tecnologías de computación, almacenamiento y bases de datos, así como ofertas serverless completamente gestionadas. El equipo de AWS Mobile ha estado colaborando estrechamente con clientes y miembros del ecosistema JavaScript para que las aplicaciones móviles y web conectadas a la nube sean más seguras, escalables y fáciles de desarrollar e implementar. Comenzamos con un kit de inicio completo, pero tenemos desarrollos más recientes.

Esta publicación de blog trata sobre aspectos interesantes para desarrolladores de React y React Native:

  • AWS Amplify, una biblioteca declarativa para aplicaciones JavaScript que utiliza servicios en la nube

  • AWS AppSync, un servicio GraphQL completamente gestionado con funciones offline y en tiempo real

AWS Amplify

Las aplicaciones de React Native son muy fáciles de iniciar usando herramientas como Create React Native App y Expo. Sin embargo, conectarlas a la nube puede ser un desafío cuando intentas alinear un caso de uso con servicios de infraestructura. Por ejemplo, tu aplicación de React Native podría necesitar subir fotos. ¿Deberían protegerse por usuario? Eso probablemente signifique que necesitas algún tipo de registro o proceso de inicio de sesión. ¿Quieres tu propio directorio de usuarios o estás usando un proveedor de redes sociales? Tal vez tu aplicación también necesite llamar a una API con lógica de negocio personalizada después de que los usuarios inicien sesión.

Para ayudar a los desarrolladores JavaScript con estos problemas, lanzamos una biblioteca llamada AWS Amplify. Su diseño se organiza en "categorías" de tareas, en lugar de implementaciones específicas de AWS. Por ejemplo, si quisieras que los usuarios se registren, inicien sesión y luego suban fotos privadas, simplemente incorporarías las categorías Auth y Storage a tu aplicación:

import { Auth } from 'aws-amplify';

Auth.signIn(username, password)
.then(user => console.log(user))
.catch(err => console.log(err));

Auth.confirmSignIn(user, code)
.then(data => console.log(data))
.catch(err => console.log(err));

En el código anterior, puedes ver un ejemplo de tareas comunes que Amplify te ayuda a realizar, como usar códigos de autenticación multifactor (MFA) con correo electrónico o SMS. Las categorías admitidas actualmente son:

  • Auth: Proporciona automatización de credenciales. La implementación lista para usar emplea credenciales de AWS para firmas y tokens JWT OIDC de Amazon Cognito. Se admite funcionalidad común, como características MFA.

  • Analytics: Con una sola línea de código, obtén seguimiento para usuarios autenticados o no autenticados en Amazon Pinpoint. Extiéndelo para métricas o atributos personalizados según prefieras.

  • API: Proporciona interacción con APIs RESTful de manera segura, aprovechando AWS Signature Version 4. El módulo API funciona excelente en infraestructuras serverless con Amazon API Gateway.

  • Storage: Comandos simplificados para subir, descargar y listar contenido en Amazon S3. También puedes agrupar datos fácilmente en contenido público o privado por usuario.

  • Caching: Interfaz de caché LRU para aplicaciones web y React Native que utiliza persistencia específica de implementación.

  • i18n and Logging: Proporciona capacidades de internacionalización y localización, así como capacidades de depuración y registro.

Una ventaja de Amplify es que codifica "mejores prácticas" en el diseño para tu entorno de programación específico. Por ejemplo, descubrimos al trabajar con clientes y desarrolladores de React Native que los atajos tomados durante el desarrollo para hacer funcionar las cosas rápidamente llegaban a entornos de producción. Estos pueden comprometer la escalabilidad o la seguridad, y forzar una reestructuración de infraestructura y refactorización de código.

Un ejemplo de cómo ayudamos a los desarrolladores a evitar esto son las Arquitecturas de Referencia Serverless con AWS Lambda. Estas muestran las mejores prácticas para usar Amazon API Gateway y AWS Lambda juntos al construir tu backend. Este patrón está integrado en la categoría API de Amplify. Puedes usar este patrón para interactuar con varios endpoints REST diferentes y pasar cabeceras directamente a tu función Lambda para lógica de negocio personalizada. También hemos lanzado una CLI de AWS Mobile para iniciar nuevos proyectos de React Native o integrarlo en existentes con estas características. Para comenzar, simplemente instala mediante npm y sigue las indicaciones de configuración:

npm install --global awsmobile-cli
awsmobile configure

Otro ejemplo de mejores prácticas integradas específicas para el ecosistema móvil es la seguridad de contraseñas. La implementación predeterminada de la categoría Auth aprovecha los grupos de usuarios de Amazon Cognito para registro e inicio de sesión. Este servicio implementa el protocolo Secure Remote Password para proteger a los usuarios durante los intentos de autenticación. Si te interesa leer sobre las matemáticas del protocolo, notarás que debes usar un número primo grande al calcular el verificador de contraseña sobre una raíz primitiva para generar un Grupo. En entornos React Native, JIT está deshabilitado. Esto hace que los cálculos BigInteger para operaciones de seguridad como esta sean menos eficientes. Para solucionarlo, hemos lanzado puentes nativos en Android e iOS que puedes vincular en tu proyecto:

npm install --save aws-amplify-react-native
react-native link amazon-cognito-identity-js

También nos emociona ver que el equipo de Expo ha incluido esto en su último SDK para que puedas usar Amplify sin necesidad de ejectar.

Finalmente, específico para desarrollo en React Native (y React), Amplify incluye componentes de orden superior (HOCs) para envolver fácilmente funcionalidades, como registro e inicio de sesión en tu aplicación:

import Amplify, { withAuthenticator } from 'aws-amplify-react-native';
import aws_exports from './aws-exports';

Amplify.configure(aws_exports);

class App extends React.Component {
...
}

export default withAuthenticator(App);

El componente subyacente también se proporciona como <Authenticator />, que te da control total para personalizar la UI. También ofrece propiedades para gestionar el estado del usuario, como si ha iniciado sesión o está esperando confirmación MFA, y callbacks que puedes activar cuando cambia el estado.

De manera similar, encontrarás componentes React genéricos para diferentes casos de uso. Puedes personalizarlos según tus necesidades, por ejemplo, para mostrar todas las imágenes privadas de Amazon S3 en el módulo Storage:

<S3Album
level="private"
path={path}
filter={(item) => /jpg/i.test(item.path)}/>

Puedes controlar muchas características de los componentes mediante props, como se mostró anteriormente con opciones de almacenamiento público o privado. Incluso hay capacidades para recopilar automáticamente análisis cuando los usuarios interactúan con ciertos componentes de UI:

return <S3Album track/>

AWS Amplify favorece un estilo de desarrollo de convención sobre configuración, con rutinas de inicialización global o por categoría. La forma más rápida de comenzar es con un archivo aws-exports. Sin embargo, los desarrolladores también pueden usar la biblioteca independientemente con recursos existentes.

Para un análisis profundo de la filosofía y ver una demo completa, mira el video de AWS re:Invent.

AWS AppSync

Poco después del lanzamiento de AWS Amplify, también lanzamos AWS AppSync. Este es un servicio GraphQL completamente administrado con capacidades tanto fuera de línea como en tiempo real. Aunque puedes usar GraphQL en diferentes lenguajes de programación cliente (incluyendo Android e iOS nativos), es muy popular entre los desarrolladores de React Native. Esto se debe a que el modelo de datos encaja perfectamente en un flujo de datos unidireccional y jerarquía de componentes.

AWS AppSync te permite conectar con recursos en tu propia cuenta de AWS, lo que significa que eres dueño y controlas tus datos. Esto se logra mediante fuentes de datos, y el servicio admite Amazon DynamoDB, Amazon Elasticsearch y AWS Lambda. Esto te permite combinar funcionalidades (como bases de datos NoSQL y búsqueda de texto completo) en una única API GraphQL como esquema. AppSync también puede aprovisionar recursos desde un esquema, así que si no estás familiarizado con los servicios de AWS, puedes escribir SDL de GraphQL, hacer clic en un botón y comenzar a operar automáticamente.

La funcionalidad en tiempo real de AWS AppSync se controla mediante suscripciones GraphQL con un patrón basado en eventos bien conocido. Como las suscripciones en AWS AppSync se controlan en el esquema con una directiva GraphQL, y un esquema puede usar cualquier fuente de datos, esto significa que puedes activar notificaciones desde operaciones de bases de datos con Amazon DynamoDB y Amazon Elasticsearch Service, o desde otras partes de tu infraestructura con AWS Lambda.

De manera similar a AWS Amplify, puedes usar funciones de seguridad empresarial en tu API GraphQL con AWS AppSync. El servicio te permite comenzar rápidamente con claves de API. Sin embargo, al pasar a producción puedes migrar a AWS Identity and Access Management (IAM) o tokens OIDC de grupos de usuarios de Amazon Cognito. Puedes controlar el acceso a nivel de resolutor con políticas en tipos. Incluso puedes usar verificaciones lógicas para control de acceso granular en tiempo de ejecución, como detectar si un usuario es propietario de un recurso específico de base de datos. También existen capacidades para verificar membresía en grupos al ejecutar resolutores o acceder a registros individuales de bases de datos.

Para ayudar a los desarrolladores de React Native a aprender sobre estas tecnologías, existe un esquema GraphQL de muestra integrado que puedes lanzar desde la página de inicio de la consola de AWS AppSync. Esta muestra implementa un esquema GraphQL, aprovisiona tablas de bases de datos y conecta automáticamente consultas, mutaciones y suscripciones. También hay un ejemplo funcional para React Native de AWS AppSync que aprovecha este esquema integrado (así como un ejemplo para React), que te permite tener tus componentes cliente y en la nube funcionando en minutos.

Comenzar es sencillo cuando usas AWSAppSyncClient, que se integra con Apollo Client. El AWSAppSyncClient maneja seguridad y firmas para tu API GraphQL, funcionalidad offline, y el proceso de handshake y negociación de suscripciones:

import AWSAppSyncClient from "aws-appsync";
import { Rehydrated } from 'aws-appsync-react';
import { AUTH_TYPE } from "aws-appsync/lib/link/auth-link";

const client = new AWSAppSyncClient({
url: awsconfig.graphqlEndpoint,
region: awsconfig.region,
auth: {type: AUTH_TYPE.API_KEY, apiKey: awsconfig.apiKey}
});

La consola de AppSync proporciona un archivo de configuración descargable que contiene tu endpoint GraphQL, región de AWS y clave de API. Luego puedes usar el cliente con React Apollo:

const WithProvider = () => (
<ApolloProvider client={client}>
<Rehydrated>
<App />
</Rehydrated>
</ApolloProvider>
);

En este punto, puedes usar consultas GraphQL estándar:

query ListEvents {
listEvents{
items{
__typename
id
name
where
when
description
comments{
__typename
items{
__typename
eventId
commentId
content
createdAt
}
nextToken
}
}
}
}

El ejemplo anterior muestra una consulta con el esquema de aplicación de muestra aprovisionado por AppSync. No solo demuestra interacción con DynamoDB, sino que también incluye paginación de datos (incluyendo tokens cifrados) y relaciones entre tipos como Events y Comments. Como la aplicación está configurada con AWSAppSyncClient, los datos se persisten automáticamente offline y se sincronizan cuando los dispositivos se reconectan.

Puedes ver un análisis profundo de la tecnología del cliente detrás de esto y una demostración de React Native en este video.

Comentarios

El equipo detrás de estas bibliotecas está deseando conocer cómo funcionan estas herramientas y servicios para ustedes. También quieren escuchar qué más podemos hacer para facilitar el desarrollo con React y React Native utilizando servicios en la nube. Pueden contactar al equipo de AWS Mobile en GitHub para AWS Amplify o AWS AppSync.

Implementando la animación de carga de la app de Twitter en React Native

· 11 min de lectura
Eli White
Eli White
Software Engineer @ Meta
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

La app de iOS de Twitter tiene una animación de carga que me gusta bastante.

Cuando la app está lista, el logo de Twitter se expande encantadoramente, revelando la aplicación.

Quería descubrir cómo recrear esta animación de carga con React Native.


Para entender cómo construirla, primero tuve que comprender las distintas partes de la animación. La mejor manera de apreciar los detalles es verla en cámara lenta.

Hay algunos elementos principales que necesitaremos descifrar cómo construir.

  1. Escalar el pájaro.

  2. Mientras el pájaro crece, mostrar la aplicación subyacente

  3. Reducir ligeramente la escala de la aplicación al final

Me tomó bastante tiempo descubrir cómo hacer esta animación.

Empecé con una suposición incorrecta: que el fondo azul y el pájaro de Twitter eran una capa encima de la aplicación y que al crecer el pájaro, se volvía transparente revelando la app debajo. ¡Este enfoque no funciona porque si el pájaro se volviera transparente, mostraría la capa azul, no la aplicación subyacente!

Afortunadamente para ti, querido lector, no tendrás que pasar por la misma frustración que yo. ¡Tienes este tutorial que va directo a lo importante!


La forma correcta

Antes de llegar al código, es importante entender cómo descomponerlo. Para visualizar este efecto, lo recreé en CodePen (incrustado en unos párrafos) para que puedas ver las capas interactivamente.

Hay tres capas principales en este efecto. La primera es la capa de fondo azul. Aunque parece estar encima de la app, en realidad está al fondo.

Luego tenemos una capa blanca lisa. Y finalmente, en primer plano, está nuestra aplicación.


El truco principal de esta animación es usar el logo de Twitter como mask (máscara) que enmascara tanto la app como la capa blanca. No profundizaré mucho en los detalles del enmascaramiento, hay muchos recursos en línea para eso.

Lo básico del enmascaramiento aquí es que los píxeles opacos de la máscara muestran el contenido que enmascaran, mientras que los píxeles transparentes lo ocultan.

Usamos el logo de Twitter como máscara para dos capas: la capa blanca sólida y la capa de la aplicación.

Para revelar la app, escalamos la máscara hasta que sea más grande que toda la pantalla.

Mientras la máscara se escala, aumentamos la opacidad de la capa de la app, mostrándola y ocultando la capa blanca detrás. Para terminar el efecto, iniciamos la capa de la app con escala >1 y la reducimos a 1 al finalizar la animación. Luego ocultamos las capas no-app ya que no se volverán a ver.

Dicen que una imagen vale mil palabras. ¿Cuántas palabras vale una visualización interactiva? Avanza por la animación con el botón "Next Step". Mostrar las capas te da una perspectiva lateral. La cuadrícula ayuda a visualizar las capas transparentes.

Ahora, con React Native

Muy bien. Ahora que sabemos qué construimos y cómo funciona la animación, podemos entrar en código — la verdadera razón por la que estás aquí.

La pieza clave de este rompecabezas es MaskedViewIOS, un componente central de React Native.

import {MaskedViewIOS} from 'react-native';

<MaskedViewIOS maskElement={<Text>Basic Mask</Text>}>
<View style={{backgroundColor: 'blue'}} />
</MaskedViewIOS>;

MaskedViewIOS recibe las props maskElement y children. Los children son enmascarados por el maskElement. Nota que la máscara no necesita ser una imagen, puede ser cualquier vista arbitraria. El comportamiento del ejemplo anterior sería renderizar la vista azul, pero solo sería visible donde las palabras "Basic Mask" aparecen desde el maskElement. Acabamos de crear texto azul complejo.

Lo que queremos hacer es renderizar nuestra capa azul, y luego encima renderizar nuestras capas enmascaradas (la app y la blanca) con el logo de Twitter.

{
fullScreenBlueLayer;
}
<MaskedViewIOS
style={{flex: 1}}
maskElement={
<View style={styles.centeredFullScreen}>
<Image source={twitterLogo} />
</View>
}>
{fullScreenWhiteLayer}
<View style={{flex: 1}}>
<MyApp />
</View>
</MaskedViewIOS>;

Esto nos dará las capas que vemos a continuación.

Ahora la parte animada

Tenemos todas las piezas necesarias para que esto funcione; el siguiente paso es animarlas. Para que esta animación se sienta fluida, utilizaremos la API Animated de React Native.

Animated nos permite definir nuestras animaciones de manera declarativa en JavaScript. Por defecto, estas animaciones se ejecutan en JavaScript y le dicen a la capa nativa qué cambios hacer en cada fotograma. Aunque JavaScript intentará actualizar la animación en cada fotograma, es probable que no pueda hacerlo lo suficientemente rápido y cause pérdida de fotogramas (jank). ¡No es lo que queremos!

Animated tiene un comportamiento especial para evitar este jank. Tiene una bandera llamada useNativeDriver que envía tu definición de animación desde JavaScript al entorno nativo al inicio de tu animación, permitiendo que el lado nativo procese las actualizaciones sin tener que comunicarse con JavaScript en cada fotograma. La desventaja de useNativeDriver es que solo puedes animar un conjunto específico de propiedades, principalmente transform y opacity. No puedes animar cosas como el color de fondo con useNativeDriver, al menos aún no; iremos agregando más propiedades con el tiempo, y por supuesto siempre puedes enviar un PR para las propiedades que necesites en tu proyecto, beneficiando a toda la comunidad 😀.

Como queremos que esta animación sea fluida, trabajaremos dentro de estas restricciones. Para una mirada más profunda sobre cómo funciona useNativeDriver internamente, consulta nuestra publicación de blog que lo anuncia.

Desglosando nuestra animación

Hay 4 componentes en nuestra animación:

  1. Agrandar el pájaro, revelando la app y la capa blanca sólida

  2. Hacer aparecer gradualmente la app (fade in)

  3. Reducir la escala de la app al final

  4. Ocultar la capa blanca y azul cuando termine

Con Animated, hay dos formas principales de definir tu animación. La primera es usando Animated.timing, que te permite especificar exactamente cuánto tiempo durará tu animación, junto con una curva de easing para suavizar el movimiento. El otro enfoque es usar las API basadas en física como Animated.spring. Con Animated.spring, especificas parámetros como la cantidad de fricción y tensión en el resorte, y dejas que la física ejecute tu animación.

Tenemos múltiples animaciones que queremos ejecutar simultáneamente y que están estrechamente relacionadas. Por ejemplo, queremos que la app comience a aparecer gradualmente mientras la máscara está a medio revelar. Debido a esta relación cercana, usaremos Animated.timing con un único Animated.Value.

Animated.Value es un envoltorio alrededor de un valor nativo que Animated usa para conocer el estado de una animación. Normalmente querrás tener solo uno de estos para una animación completa. La mayoría de componentes que usan Animated almacenarán este valor en el estado.

Como estoy pensando en esta animación como pasos que ocurren en diferentes momentos a lo largo de la secuencia completa, comenzaremos nuestro Animated.Value en 0 (representando 0% completado) y terminaremos en 100 (representando 100% completado).

El estado inicial de nuestro componente será el siguiente:

state = {
loadingProgress: new Animated.Value(0),
};

Cuando estemos listos para comenzar la animación, le diremos a Animated que anime este valor hasta 100.

Animated.timing(this.state.loadingProgress, {
toValue: 100,
duration: 1000,
useNativeDriver: true, // This is important!
}).start();

Luego intento calcular una estimación aproximada de las diferentes partes de las animaciones y los valores que deberían tener en distintas etapas de la animación general. A continuación se muestra una tabla con las diferentes partes de la animación y los valores que considero deberían tener en distintos puntos a medida que avanzamos en el tiempo.

La máscara del pájaro de Twitter debe comenzar con escala 1, y se hace más pequeña antes de aumentar rápidamente de tamaño. Así que al 10% de la animación, debería tener un valor de escala de 0.8 antes de aumentar hasta escala 70 al final. Elegir 70 fue bastante arbitrario, la verdad; necesitaba ser lo suficientemente grande para que el pájaro revelara completamente la pantalla y 60 no alcanzaba 😀. Algo interesante de esta parte es que cuanto más alto sea el número, más rápido parecerá crecer porque debe llegar allí en el mismo tiempo. Este número requirió varias pruebas hasta lograr que se viera bien con este logo. Logotipos o dispositivos de diferentes tamaños requerirán que esta escala final sea diferente para garantizar que toda la pantalla quede revelada.

La aplicación debe permanecer opaca durante un tiempo, al menos mientras el logo de Twitter se hace más pequeño. Según la animación oficial, quiero comenzar a mostrarla cuando el pájaro esté a mitad de camino en su aumento y revelarla completamente bastante rápido. Así que al 15% comenzamos a mostrarla, y al 30% de la animación total ya es completamente visible.

La escala de la aplicación comienza en 1.1 y se reduce hasta su escala normal al final de la animación.

Y ahora, en código.

Esencialmente, lo que hicimos anteriormente es mapear los valores del porcentaje de progreso de la animación a los valores de las piezas individuales. Hacemos esto con Animated usando .interpolate. Creamos 3 objetos de estilo diferentes, uno para cada parte de la animación, usando valores interpolados basados en this.state.loadingProgress.

const loadingProgress = this.state.loadingProgress;

const opacityClearToVisible = {
opacity: loadingProgress.interpolate({
inputRange: [0, 15, 30],
outputRange: [0, 0, 1],
extrapolate: 'clamp',
// clamp means when the input is 30-100, output should stay at 1
}),
};

const imageScale = {
transform: [
{
scale: loadingProgress.interpolate({
inputRange: [0, 10, 100],
outputRange: [1, 0.8, 70],
}),
},
],
};

const appScale = {
transform: [
{
scale: loadingProgress.interpolate({
inputRange: [0, 100],
outputRange: [1.1, 1],
}),
},
],
};

Ahora que tenemos estos objetos de estilo, podemos usarlos al renderizar el fragmento de la vista que vimos antes en la publicación. Ten en cuenta que solo Animated.View, Animated.Text y Animated.Image pueden usar objetos de estilo que empleen Animated.Value.

const fullScreenBlueLayer = (
<View style={styles.fullScreenBlueLayer} />
);
const fullScreenWhiteLayer = (
<View style={styles.fullScreenWhiteLayer} />
);

return (
<View style={styles.fullScreen}>
{fullScreenBlueLayer}
<MaskedViewIOS
style={{flex: 1}}
maskElement={
<View style={styles.centeredFullScreen}>
<Animated.Image
style={[styles.maskImageStyle, imageScale]}
source={twitterLogo}
/>
</View>
}>
{fullScreenWhiteLayer}
<Animated.View
style={[opacityClearToVisible, appScale, {flex: 1}]}>
{this.props.children}
</Animated.View>
</MaskedViewIOS>
</View>
);

¡Yay! Ahora tenemos las partes de la animación luciendo como queremos. Solo nos queda limpiar nuestras capas azul y blanca que nunca volverán a verse.

Para saber cuándo podemos limpiarlas, necesitamos saber cuándo se completa la animación. Por suerte, cuando llamamos a Animated.timing, .start recibe un callback opcional que se ejecuta cuando la animación termina.

Animated.timing(this.state.loadingProgress, {
toValue: 100,
duration: 1000,
useNativeDriver: true,
}).start(() => {
this.setState({
animationDone: true,
});
});

Ahora que tenemos un valor en state para saber si hemos terminado con la animación, podemos modificar nuestras capas azul y blanca para que lo utilicen.

const fullScreenBlueLayer = this.state.animationDone ? null : (
<View style={[styles.fullScreenBlueLayer]} />
);
const fullScreenWhiteLayer = this.state.animationDone ? null : (
<View style={[styles.fullScreenWhiteLayer]} />
);

¡Voilà! Nuestra animación ahora funciona y limpiamos las capas no utilizadas una vez que termina. ¡Hemos construido la animación de carga de la app de Twitter!

¡Pero espera, el mío no funciona!

No te preocupes, querido lector. Yo también odio cuando las guías solo dan fragmentos de código sin proporcionar el código completo.

Este componente ha sido publicado en npm y está en GitHub como react-native-mask-loader. Para probarlo en tu teléfono, está disponible en Expo aquí:

Más lecturas / Crédito extra

  1. Este gitbook es un gran recurso para aprender más sobre Animated después de leer la documentación de React Native.

  2. La animación real de Twitter parece acelerar la revelación de la máscara hacia el final. Intenta modificar el loader para usar una función de easing diferente (¡o un spring!) para igualar mejor ese comportamiento.

  3. La escala final actual de la máscara está codificada y probablemente no revelará toda la aplicación en una tablet. Calcular la escala final basada en el tamaño de pantalla y el tamaño de la imagen sería un PR increíble.

React Native Mensual #6

· 4 min de lectura
Tomislav Tenodi
Fundador en Speck
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

¡La reunión mensual de React Native sigue con fuerza! Asegúrate de revisar la nota al final de esta publicación para las próximas sesiones.

Expo

  • Felicitaciones a Devin Abbott y Houssein Djirdeh por el prelanzamiento de su libro "Full Stack React Native". Te guía en el aprendizaje de React Native mediante la construcción de varias aplicaciones pequeñas.

  • Lanzada la primera versión (experimental) de reason-react-native-scripts para ayudar a las personas a probar fácilmente ReasonML.

  • ¡El SDK 24 de Expo ha sido lanzado! Utiliza React Native 0.51 e incluye un conjunto de nuevas funciones y mejoras: empaquetado de imágenes en aplicaciones independientes (¡sin necesidad de caché en la primera carga!), API de manipulación de imágenes (recortar, redimensionar, rotar, voltear), API de detección facial, nuevas funciones de canales de lanzamiento (establecer el lanzamiento activo para un canal dado y revertir), panel web para rastrear compilaciones de aplicaciones independientes, y una corrección para un error persistente con la implementación de OpenGL en Android y el multitarea de Android, por nombrar solo algunas cosas.

  • Estamos asignando más recursos a React Navigation a partir de este enero. Creemos firmemente que es posible y deseable construir navegación en React Native usando solo componentes de React y primitivas como Animated y react-native-gesture-handler, y estamos muy entusiasmados con algunas de las mejoras que planeamos. Si buscas contribuir a la comunidad, revisa react-native-maps y react-native-svg, ¡ambos podrían usar ayuda!

Infinite Red

Microsoft

  • Se ha iniciado un pull request para migrar el núcleo del puente de React Native Windows a .NET Standard, haciéndolo efectivamente independiente del sistema operativo. La esperanza es que muchas otras plataformas .NET Core puedan extender el puente con sus propios modelos de subprocesos, entornos de ejecución JavaScript y UIManagers (piensa en JavaScriptCore, Xamarin.Mac, Linux Gtk# y opciones Samsung Tizen).

Wix

  • Detox

    • Para escalar con pruebas E2E, queremos minimizar el tiempo en CI; estamos trabajando en soporte de paralelización para Detox.
    • Se ha enviado un pull request para habilitar soporte para compilaciones de sabores personalizados, mejorando el soporte para mocks en E2E.
  • DetoxInstruments

    • Desarrollar la función principal de DetoxInstruments está siendo un desafío complejo: capturar backtraces de JavaScript en cualquier momento requiere una implementación personalizada de JSCore que soporte suspensión del hilo JS. Las pruebas internas del perfilador en la app de Wix revelaron hallazgos interesantes sobre el comportamiento del hilo JS.
    • El proyecto aún no es lo suficientemente estable para uso general, pero estamos trabajando activamente y esperamos anunciarlo pronto.
  • React Native Navigation

    • ¡El desarrollo de la V2 ha acelerado significativamente! Pasamos de tener 1 desarrollador dedicando 20% de su tiempo a contar con 3 desarrolladores trabajando a tiempo completo.
  • Rendimiento en Android

    • Reemplazar la versión antigua de JSCore incluida en RN por la más reciente (versión de punta del proyecto webkitGTK con configuración JIT personalizada) generó un 40% de mejora en el hilo JS. El próximo paso es compilar una versión de 64 bits. Este trabajo se basa en los scripts de compilación JSC para Android. Puedes seguir su estado actual aquí.

Próximas sesiones

Estamos evaluando reorientar estas reuniones para enfocarnos en temas específicos (como navegación, migración de módulos a repositorios independientes o documentación). Creemos que así podremos contribuir mejor a la comunidad de React Native. Esta modalidad podría implementarse en la próxima sesión. ¡Tuitea qué temas te gustaría que abordáramos!

React Native Mensual #5

· 4 min de lectura
Tomislav Tenodi
Fundador en Speck
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

¡La reunión mensual de React Native continúa! Veamos en qué están trabajando nuestros equipos.

Callstack

  • Hemos trabajado en la CI de React Native. Lo más importante es que migramos de Travis a CircleCI, dejando a React Native con una única canalización de CI unificada.

  • Organizamos el Hacktoberfest - edición React Native donde, junto a los participantes, intentamos enviar numerosas pull requests a proyectos de código abierto.

  • Seguimos desarrollando Haul. El mes pasado lanzamos dos nuevas versiones con soporte para webpack 3. Planeamos añadir compatibilidad con CRNA y Expo, además de mejorar el HMR. Nuestra hoja de ruta está pública en el issue tracker. Si deseas sugerir mejoras o dar feedback, ¡avísanos!

Expo

  • Lanzamos Expo SDK 22 (con React Native 0.49) y actualizamos CRNA para esta versión.

    • Incluye API mejorada para pantallas de inicio, soporte básico para ARKit, API "DeviceMotion", compatibilidad con SFAuthenticationSession en iOS11 y más.
  • Tus snacks ahora admiten múltiples archivos JavaScript y puedes subir imágenes y otros assets arrastrándolos directamente al editor.

  • Contribuimos a react-navigation para añadir soporte para iPhone X.

  • Enfocamos nuestra atención en problemas comunes al crear aplicaciones grandes con Expo. Por ejemplo:

    • Soporte nativo para despliegues en múltiples entornos: staging, producción y canales personalizados. Los canales admitirán rollbacks y configuración de releases activas. Avísanos si quieres ser tester inicial @expo_io.
    • También mejoramos nuestra infraestructura para construir apps independientes, añadiendo soporte para incluir imágenes y assets no-code en builds finales manteniendo la capacidad de actualizarlos vía OTA.

Facebook

  • Mejor soporte RTL:

    • Introducimos estilos sensibles a la dirección:
      • Posición:
        • (left|right) → (start|end)
      • Márgenes:
        • margin(Left|Right) → margin(Start|End)
      • Relleno:
        • padding(Left|Right) → padding(Start|End)
      • Bordes:
        • borderTop(Left|Right)Radius → borderTop(Start|End)Radius
        • borderBottom(Left|Right)Radius → borderBottom(Start|End)Radius
        • border(Left|Right)Width → border(Start|End)Width
        • border(Left|Right)Color → border(Start|End)Color
    • Los significados de "left" y "right" se intercambiaban en RTL para estilos de posición, márgenes, relleno y bordes. En unos meses eliminaremos este comportamiento haciendo que "left" siempre signifique izquierda y "right" siempre signifique derecha. Estos cambios son breaking y están ocultos tras un flag. Usa I18nManager.swapLeftAndRightInRTL(false) en tus componentes para activarlos.
  • Trabajamos en tipar nuestros módulos nativos internos con Flow y usarlos para generar interfaces en Java y protocolos en ObjC que las implementaciones nativas deben seguir. Esperamos que este sistema de codegen sea open source el próximo año como muy pronto.

Infinite Red

  • Nueva herramienta de código abierto para ayudar a React Native y otros proyectos. Más información aquí.

  • Actualizando Ignite para una nueva versión de boilerplate (Nombre en código: Bowser)

Shoutem

  • Mejorando el flujo de desarrollo en Shoutem. Queremos simplificar el proceso desde crear una app hasta la primera pantalla personalizada, haciéndolo realmente sencillo para reducir la barrera de entrada de nuevos desarrolladores React Native. Preparamos talleres para probar nuevas funcionalidades. También mejoramos Shoutem CLI para soportar estos nuevos flujos.

  • Shoutem UI recibió mejoras en componentes y correcciones de errores. También verificamos compatibilidad con las últimas versiones de React Native.

  • La plataforma Shoutem recibió actualizaciones importantes, con nuevas integraciones disponibles como parte del proyecto open-source de extensiones. Nos entusiasma ver desarrollo activo en extensiones de Shoutem por otros desarrolladores. Contactamos activamente ofreciendo asesoría y guía sobre sus extensiones.

Próxima sesión

La próxima sesión está programada para el miércoles 6 de diciembre de 2017. No dudes en contactarme en Twitter si tienes sugerencias para mejorar los resultados de estas reuniones.

React Native Monthly #4

· 4 min de lectura
Mike Grabowski
Mike Grabowski
CTO and Co-Founder @ Callstack
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

¡Continuamos con la reunión mensual de React Native! Estas son las notas de cada equipo:

Callstack

  • React Native EU ha concluido. Más de 300 participantes de 33 países visitaron Wroclaw. Las charlas están disponibles en YouTube.

  • Estamos retomando gradualmente nuestro ritmo de trabajo en código abierto después de la conferencia. Un punto destacable es que estamos preparando una nueva versión de react-native-opentok que solucionará la mayoría de los problemas existentes.

GeekyAnts

Trabajando para reducir las barreras de entrada para desarrolladores que adoptan React Native con estas iniciativas:

  • Anunciamos BuilderX.io en React Native EU. BuilderX es una herramienta de diseño que trabaja directamente con archivos JavaScript (actualmente solo soporta React Native) para generar código elegante, legible y editable.

  • Lanzamos ReactNativeSeed.com, que ofrece plantillas para tu próximo proyecto en React Native. Incluye diversas opciones como TypeScript & Flow para tipos de datos, MobX, Redux y mobx-state-tree para gestión de estado, con CRNA y React-Native básico como stack.

Expo

  • Pronto lanzaremos el SDK 21, que añade soporte para react-native 0.48.3 junto con correcciones de errores, mejoras de fiabilidad y nuevas funciones en Expo SDK, incluyendo grabación de video, nueva API para pantallas de inicio, soporte para react-native-gesture-handler y mejor manejo de errores.

  • Respecto a react-native-gesture-handler, Krzysztof Magiera de Software Mansion continúa avanzando en este proyecto. Hemos colaborado en pruebas y financiado parte de su desarrollo. Su integración en Expo SDK21 permitirá probarlo fácilmente en Snack, así que estamos emocionados por ver qué crea la comunidad.

  • Sobre mejoras en registro/manejo de errores: consulta este gist de un PR interno de Expo para detalles del registro (especialmente "Problema 2"), y este commit para cambios en el manejo de importaciones fallidas de módulos estándar de npm. Existen oportunidades para mejorar mensajes de error en React Native mediante este enfoque, y trabajaremos en PRs posteriores. Sería excelente que la comunidad participe también.

  • native.directory sigue creciendo; puedes añadir tus proyectos desde el repositorio de GitHub.

  • Asistiremos a hackathons en Norteamérica, incluyendo PennApps, Hack The North, HackMIT y próximamente MHacks.

Facebook

  • Mejorando componentes <Text> y <TextInput> en Android (crecimiento automático nativo para <TextInput>; problemas de diseño en componentes <Text> anidados; mejor estructura de código; optimizaciones de rendimiento).

  • Seguimos buscando colaboradores adicionales que deseen ayudar en la gestión de issues y pull requests.

Microsoft

  • Lanzada función de Firma de Código para CodePush. Los desarrolladores de React Native ahora pueden firmar sus paquetes de aplicación en CodePush. El anuncio está disponible aquí

  • Trabajando en completar la integración de CodePush en Mobile Center. También evaluando la integración de pruebas y gestión de fallos.

Próxima sesión

La próxima sesión está programada para el miércoles 10 de octubre de 2017. Como esta fue solo nuestra cuarta reunión, nos gustaría saber cómo estas notas benefician a la comunidad de React Native. No dudes en contactarme en Twitter si tienes sugerencias sobre cómo mejorar los resultados de nuestras reuniones.

Resumen Mensual de React Native #3

· 5 min de lectura
Mike Grabowski
Mike Grabowski
CTO and Co-Founder @ Callstack
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

¡Continuamos con la reunión mensual de React Native! Este mes el encuentro fue más breve porque la mayoría de nuestros equipos estaban ocupados lanzando productos. El próximo mes estaremos en la conferencia React Native EU en Wroclaw, Polonia. ¡Asegúrate de conseguir tu entrada y nos vemos allí en persona! Mientras tanto, veamos en qué están trabajando nuestros equipos.

Equipos

En esta tercera reunión, nos acompañaron 5 equipos:

Notas

Estas son las notas de cada equipo:

Callstack

  • Recientemente hicimos open source de react-native-material-palette. Extrae colores prominentes de las imágenes para ayudarte a crear aplicaciones visualmente atractivas. Actualmente solo está disponible para Android, pero estamos evaluando añadir soporte para iOS en el futuro.

  • Hemos implementado soporte para HMR en haul junto con otras funcionalidades interesantes. ¡Consulta los últimos lanzamientos!

  • ¡React Native EU 2017 se acerca! ¡El próximo mes estará dedicado a React Native y Polonia! Asegúrate de conseguir las últimas entradas disponibles aquí.

Expo

  • Lanzamos soporte para instalar paquetes npm en Snack. Se aplican las restricciones habituales de Expo: los paquetes no pueden depender de APIs nativas personalizadas que no estén ya incluidas en Expo. También estamos trabajando en la compatibilidad con múltiples archivos y carga de recursos en Snack. Satyajit hablará sobre Snack en React Native Europe.

  • Lanzamos SDK20 con cámara, pagos, almacenamiento seguro, magnetómetro, pausar/reanudar descargas fs y pantalla de inicio/carga mejorada.

  • Seguimos colaborando con Krzysztof en react-native-gesture-handler. Por favor pruébalo, reconstruye algún gesto que hayas implementado antes usando PanResponder o reconocedores de gestos nativos y cuéntanos qué problemas encuentras.

  • Experimentando con el protocolo de depuración de JSC, trabajando en varias solicitudes de características en Canny.

Facebook

  • El mes pasado discutimos la gestión del rastreador de problemas en GitHub y cómo intentaríamos realizar mejoras para abordar la mantenibilidad del proyecto.

  • Actualmente, el número de problemas abiertos se mantiene estable alrededor de 600, y parece que podría continuar así por un tiempo. En el último mes, cerramos 690 problemas por inactividad (definida como ningún comentario en los últimos 60 días). De esos 690 problemas, 58 se reabrieron por diversas razones (un mantenedor se comprometió a solucionarlo, o un colaborador presentó argumentos sólidos para mantener el problema abierto).

  • Planeamos continuar con el cierre automatizado de issues inactivos en el futuro previsible. Queremos llegar a un estado donde cada issue significativo abierto en el tracker sea atendido, pero aún no estamos allí. Necesitamos toda la ayuda posible de los mantenedores para triar issues y asegurarnos de no pasar por alto aquellos que introducen regresiones o cambios disruptivos, especialmente los que afectan proyectos recién creados. Las personas interesadas en ayudar pueden usar el Facebook GitHub Bot para triar issues y pull requests. La nueva Guía para Mantenedores contiene más información sobre triaje y uso del GitHub Bot. ¡Por favor añádete al equipo de fuerza de issues y anima a otros miembros activos de la comunidad a hacer lo mismo!

Microsoft

  • La nueva aplicación Skype está construida sobre React Native para facilitar compartir la mayor cantidad de código posible entre plataformas. La aplicación Skype basada en React Native ya está disponible en las tiendas de aplicaciones de Android e iOS.

  • Mientras construíamos la aplicación Skype con React Native, enviamos pull requests a React Native para solucionar errores y características faltantes que encontramos. Hasta ahora, hemos logrado que se fusionen alrededor de 70 pull requests.

  • React Native nos permitió impulsar las aplicaciones Skype para Android e iOS desde la misma base de código. También queremos usar esa base de código para impulsar la aplicación web de Skype. Para ayudarnos a lograr ese objetivo, construimos y publicamos como código abierto una capa delgada sobre React/React Native llamada ReactXP. ReactXP proporciona un conjunto de componentes multiplataforma que se asignan a React Native cuando se dirige a iOS/Android y a react-dom cuando se dirige a la web. Los objetivos de ReactXP son similares a otra biblioteca de código abierto llamada React Native for Web. Hay una breve descripción de cómo difieren los enfoques de estas bibliotecas en las FAQ de ReactXP.

Shoutem

  • Continuamos nuestros esfuerzos para mejorar y simplificar la experiencia del desarrollador al crear aplicaciones usando Shoutem.

  • Comenzamos a migrar todas nuestras aplicaciones a react-navigation, pero terminamos posponiendo esto hasta que se lance una versión más estable o alguna de las soluciones de navegación nativa se estabilice.

  • Actualizando todas nuestras extensiones y la mayoría de nuestras bibliotecas de código abierto (animation, theme, ui) a React Native 0.47.1.

Próxima sesión

La próxima sesión está programada para el miércoles 13 de septiembre de 2017. Como esta fue solo nuestra tercera reunión, nos gustaría saber cómo estas notas benefician a la comunidad de React Native. No dudes en contactarme en Twitter si tienes alguna sugerencia sobre cómo deberíamos mejorar los resultados de la reunión.

Rendimiento de React Native en Marketplace

· 6 min de lectura
Ingeniero de Software en Facebook
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

React Native se utiliza en múltiples lugares de diversas aplicaciones de la familia Facebook, incluida una pestaña principal en las aplicaciones principales de Facebook. El enfoque de este artículo es un producto altamente visible: Marketplace. Está disponible en una docena de países y permite a los usuarios descubrir productos y servicios ofrecidos por otros usuarios.

En el primer semestre de 2017, mediante el esfuerzo conjunto del equipo Relay, el equipo Marketplace, el equipo de Plataforma JS Móvil y el equipo React Native, redujimos a la mitad el Tiempo hasta la Interacción (TTI) de Marketplace en dispositivos Android de Year Class 2010-11. Facebook históricamente ha considerado estos dispositivos como Android de gama baja, y presentan los TTIs más lentos en cualquier plataforma o tipo de dispositivo.

Un inicio típico de React Native se ve así:

Aclaración: las proporciones no son representativas y variarán según cómo se configure y utilice React Native.

Primero inicializamos el núcleo de React Native (también llamado "Bridge") antes de ejecutar el JavaScript específico del producto, que determina qué vistas nativas renderizará React Native durante el Tiempo de Procesamiento Nativo.

Un enfoque diferente

Uno de nuestros primeros errores fue permitir que Systrace y CTScan guiaran nuestros esfuerzos de rendimiento. Estas herramientas nos ayudaron a encontrar muchas mejoras fáciles en 2016, pero descubrimos que tanto Systrace como CTScan no representan escenarios de producción reales y no pueden emular lo que ocurre en entornos reales. Las proporciones de tiempo en los desgloses suelen ser incorrectas y, a veces, completamente desacertadas. En casos extremos, algunas operaciones que esperábamos tomaran milisegundos tardaban cientos o miles de milisegundos. Dicho esto, CTScan es útil y hemos comprobado que detecta un tercio de las regresiones antes de que lleguen a producción.

En Android, atribuimos las limitaciones de estas herramientas a tres factores: 1) React Native es un framework multihilo, 2) Marketplace coexiste con múltiples vistas complejas como Newsfeed y otras pestañas principales, y 3) los tiempos de cálculo varían enormemente. Por ello, este semestre dejamos que las mediciones y desgloses de producción guiaran casi todas nuestras decisiones y priorizaciones.

Siguiendo el camino de la instrumentación en producción

Instrumentar la producción puede parecer simple superficialmente, pero resultó ser un proceso bastante complejo. Tomó múltiples ciclos de iteración de 2-3 semanas cada uno; debido a la latencia desde integrar un commit en master, hasta publicar la app en Play Store, y recopilar suficientes muestras de producción para validar nuestro trabajo. Cada ciclo implicaba verificar si nuestros desgloses eran precisos, si tenían el nivel adecuado de granularidad y si sumaban correctamente al tiempo total. No podíamos confiar en versiones alpha y beta porque no representan a la población general. En esencia, construimos meticulosamente un rastreo de producción muy preciso basado en millones de muestras agregadas.

Una razón por la que verificamos meticulosamente que cada milisegundo en los desgloses sumara correctamente a sus métricas padre fue que descubrimos vacíos en nuestra instrumentación. Resultó que nuestros desgloses iniciales no contabilizaban las pausas causadas por saltos entre hilos. Los saltos de hilo en sí no son costosos, pero saltar a hilos ocupados que ya están trabajando es muy costoso. Finalmente reproducimos estos bloqueos localmente agregando llamadas Thread.sleep() en momentos clave, y los solucionamos mediante:

  1. eliminar nuestra dependencia de AsyncTask,

  2. revertir la inicialización forzada de ReactContext y NativeModules en el hilo UI, y

  3. eliminar la dependencia de medir ReactRootView durante la inicialización.

Juntos, la eliminación de estos problemas de bloqueo de hilos redujo el tiempo de inicio en más de un 25%.

Las métricas de producción también desafiaron algunas de nuestras suposiciones anteriores. Por ejemplo, solíamos precargar muchos módulos de JavaScript en la ruta de inicio bajo el supuesto de que ubicar módulos juntos en un único paquete reduciría su costo de inicialización. Sin embargo, el costo de precargar y colocar estos módulos superó ampliamente los beneficios. Al reconfigurar nuestras listas negras de requerimientos en línea y eliminar módulos de JavaScript de la ruta de inicio, pudimos evitar cargar módulos innecesarios como Relay Classic (cuando solo Relay Modern era necesario). Hoy, nuestro desglose RUN_JS_BUNDLE es más de un 75% más rápido.

También encontramos mejoras al investigar módulos nativos específicos del producto. Por ejemplo, al inyectar de manera diferida las dependencias de un módulo nativo, redujimos el costo de ese módulo nativo en un 98%. Al eliminar la contención del inicio de Marketplace con otros productos, reducimos el inicio en un intervalo equivalente.

Lo mejor es que muchas de estas mejoras son ampliamente aplicables a todas las pantallas construidas con React Native.

Conclusión

La gente asume que los problemas de rendimiento en el inicio de React Native son causados por JavaScript lento o tiempos de red excesivamente altos. Si bien acelerar cosas como JavaScript reduciría el TTI en una cantidad no trivial, cada uno de estos factores contribuye con un porcentaje mucho menor del TTI de lo que se creía anteriormente.

La lección hasta ahora ha sido: ¡mide, mide, mide! Algunas mejoras provienen de trasladar costos de tiempo de ejecución al tiempo de compilación, como Relay Modern y los Módulos Nativos Diferidos. Otras mejoras provienen de evitar trabajo al ser más inteligentes sobre la paralelización de código o eliminar código muerto. Y algunas mejoras provienen de grandes cambios arquitectónicos en React Native, como limpiar bloqueos de hilos. No existe una solución grandiosa para el rendimiento, y las mejoras de rendimiento a largo plazo provendrán de instrumentación incremental y optimizaciones. No permitas que el sesgo cognitivo influya en tus decisiones. En su lugar, recopila e interpreta cuidadosamente datos de producción para guiar el trabajo futuro.

Planes futuros

A largo plazo, queremos que el TTI de Marketplace sea comparable al de productos similares construidos nativamente y, en general, que el rendimiento de React Native esté a la par del rendimiento nativo. Además, aunque este semestre redujimos drásticamente el costo de inicio del puente en aproximadamente un 80%, planeamos llevar el costo del puente de React Native cerca de cero mediante proyectos como Prepack y más procesamiento en tiempo de compilación.