
La tarea de comparar marcos es una tarea muy ingrata, las preferencias de los desarrolladores son diferentes, las tecnologías cambian muy rápidamente. Demasiado rápido Este artículo quedará obsoleto incluso antes de hacer clic en el botón publicar.
Hubo intentos de comparar, por ejemplo, hace unos cinco años, los muchachos (Colin Eberhardt y Chris Price) inspiraron a varios desarrolladores a hacer una aplicación para buscar bienes raíces de acuerdo con los conocimientos tradicionales claramente compilados. La idea es genial, incluso participamos e hicimos una versión de esta aplicación en
DevExtreme . Pero en términos de apoyo, tal proyecto es un infierno y ahora el proyecto
Property Cross representa una cierta capa histórica que causa nostalgia y sentimientos cálidos, pero difícilmente es de uso práctico.
Si tomamos solo el mundo js, es decir, un proyecto
todomvc bastante animado que compara solo la parte js, sin empaquetar en un móvil, escritorio o cualquier aplicación. El proyecto es animado y respaldado. Lo más probable es que todavía haya ejemplos muy interesantes que no notamos en Google cuando estábamos preparando el artículo, pero no nos molestará.
Nuestro experimento es menos ambicioso y muestra solo la sección actual de tecnologías, incluso una pequeña parte de ella. Aquí hay un enlace al
primer y
segundo artículo del experimento.
Más información es el tercer artículo sobre cómo hacer una aplicación en React Native de acuerdo con TK. Es muy similar a cientos, y tal vez miles, de otro recuento de documentación sobre cómo hacer una aplicación en React Native. Querido lector, te lo advertí, mi conciencia está limpia.
Recuerda TK
En general, se puede ver completamente en el primer artículo. Pero agregaré una imagen de lo que debería resultar al final. Hay pocas fotos.

Una pizca de equipo. ¿Qué es React Native?
React Native es un marco para crear aplicaciones móviles multiplataforma desde Facebook. Al igual que en el React "regular" para la web, la aplicación de interfaz de usuario se ensambla a partir de ladrillos, componentes que responden a los cambios en su estado (estado) y las propiedades que se les pasan (accesorios), pero, a diferencia de la web, se representan en controles nativos.
Idealmente, se utilizan los principios de inmunidad y funciones puras, lo que garantiza la simplicidad y el aislamiento de las pruebas. Y aquí vale la pena señalar que React en sí es muy simple, y esta simplicidad entra en la parte móvil.
Los complementos adicionales en código nativo y JS suavizan la diferencia entre plataformas cuando es posible. De hecho, React Native proporciona cierta unificación de las propiedades del componente en cada sistema operativo.
Por ejemplo, ScrollView y HorizontalScrollView son 2 componentes diferentes en Android. Y en iOS UIScrollView, que admite desplazamiento horizontal y vertical. Y en React Native usaremos el siguiente código multiplataforma:
<ScrollView horizontal={true}/>
Con un enfoque competente, obtenemos una aplicación nativa "honesta" que se ejecuta en iOS y Android.
En un mundo ideal, cuando se desarrolla en React Native, no tiene que escribir en Java u Objective-C. Pero existe esa oportunidad cuando necesita implementar un componente que va más allá de las capacidades de React Native.
Los desarrolladores de Airbnb jugaron mucho con esto, y podemos ver muchas implementaciones valiosas en la comunidad que anteriormente estaban en su repositorio. Por ejemplo,
Lottie es una biblioteca para importar animaciones de Adobe After Effects o
mapas multiplataforma .
El código JS en la aplicación se ejecuta en el motor
JavaScriptCore . La comunicación entre el código nativo y JS se realiza mediante un puente asíncrono (bridge), que le permite transferir propiedades (accesorios), desencadenar eventos (eventos) y devoluciones de llamada.

Imagen tomada de la excelente documentación
React Made Native Easy . (Recomiendo encarecidamente leer).
Durante el proceso de compilación, se usa babel nuevo para convertir el código JS, esto le permite usar la nueva sintaxis de ES6, así como algunas características de ES8 (por ejemplo, async-wait). Si usted, mi querido lector, es un desarrollador de js, comprenderá lo bueno que es cuando hay un operador de propagación y lo malo que es cuando no lo es.
Para el diseño de la página, se utiliza la tecnología flexbox, implementada por el motor de yoga multiplataforma. Tiene diferencias con el navegador flexbox, pero son insignificantes y se relacionan principalmente con los valores predeterminados. Por supuesto, hay matices, pero tendrás suerte, y todo será solo de acuerdo con la documentación.
Preparación e implementación de la pila. Terminal de tubo
Para trabajar con RN, necesitamos
Node.js y el administrador de paquetes npm, que viene incluido. No es necesario, pero es muy conveniente instalar la aplicación
Expo en su dispositivo. Le permitirá iniciar nuestro proyecto en su teléfono, así como crear y ejecutar una aplicación iOS cuando no tenga a mano macOS.
Vamos a crear una nueva aplicación. Para hacer esto, use el paquete
create-react-native-app .
En la terminal, ejecute:
npm install -g create-react-native-app create-react-native-app notes cd notes npm run start
Escanee el código QR usando Expo o ingrese un enlace desde la terminal, o incluso envíe el enlace a su teléfono, directamente desde la terminal.
En general, sospecho que los desarrolladores de cli para reaccionar nativos tenían un anciano canoso que encontró juguetes roguelike sin interfaz de usuario cuando solo hay un terminal y, en lugar de una tarjeta de video de gama alta, solo su imaginación.

Pero, mientras tanto, acabamos de crear y lanzar la aplicación "Hello World".
Y todo el "Hola Mundo" -a no es suficiente. Analizar TK
Según la declaración de trabajo, la estructura de datos de la aplicación será
Note: { userName: string, avatar: string, editTime: string, text: string } Project: { name: string, notes: Array<Note> } Projects: Array<Project>
Para trabajar con esos datos, tomaría una solución muy moderna basada en CQRS. Esto permitiría preservar la integridad de los datos, proporcionando una alta velocidad de lectura con la capacidad de reorganizar las proyecciones, así como una implementación rápida en la nube con un solo comando. Como
Resolve , desarrollado por nuestros colegas.
Pero no lo tomaré, tenemos un experimento simple, sin backend. Y para simplificar, utilizaré la arquitectura de
flujo , en particular su implementación:
redux . Los datos del estado de la aplicación llegan a los componentes como accesorios. Los componentes pueden llamar a acciones para actualizar datos.
La aplicación tendrá 3 pantallas, todas de acuerdo con los ToR:
- lista de proyectos - Proyectos,
- página detallada del proyecto con una lista de notas - Proyecto,
- página de notas detalladas - Nota
Para la navegación entre pantallas, usaré la biblioteca estándar
de navegación de reacción . Los números cerca del gráfico en la página de la biblioteca muestran cuántas veces se descarga por semana. Ahora hay alrededor de 100 mil por semana. Es bueno que no haya sido el único que eligió dicha biblioteca para la navegación. Y sí, puede ver los dígitos de otros paquetes npm que indiqué en este artículo para comprender aproximadamente el número de usuarios de esta tecnología en un momento dado.
Crea una aplicación
Para React Native, el componente de aplicación del archivo App.js es el punto de entrada a la aplicación.
export default class App extends Component { render() { return ( <Provider store={store}> <Navigator /> </Provider> ) } }
El componente de proveedor conecta la tienda con datos y el estado de la aplicación desde la biblioteca react-redux. Esto proporciona el reenvío de datos para componentes anidados.
Cree un navegador para las transiciones entre pantallas en la aplicación. Refleja claramente la estructura de la aplicación, declarada en el experimento, y dibuja transiciones animadas entre pantallas para cada plataforma.
const Navigator = createStackNavigator({ Projects: { screen: Projects }, Project: { screen: Project }, Note: { screen: Note } })
Las pantallas del navegador son componentes, contenedores. Obtienen datos del estado de la aplicación.
Lista de proyectos - Proyectos
En la pantalla con una lista de proyectos, habrá una lista y un botón para agregar un proyecto, en el encabezado de la ventana de la derecha. Crearemos un nuevo proyecto en la pantalla Proyecto.
Para la navegación, utilizamos el objeto de navegación, que pasó a los accesorios el componente principal: el navegador.
export class Projects extends PureComponent { static navigationOptions = ({ navigation }) => ({ headerRight: ( <AddButton onPress={() => navigation.navigate('Project')} /> ) }) navigateProject = project => { this.props.navigation.navigate('Project', { projectId: project.id, name: project.name }) } render() { return ( <ProjectList projects={this.props.projects} onPressProject={this.navigateProject} /> ) } }
Para mostrar la lista de proyectos, utilizaremos FlatList, una lista multiplataforma con virtualización:
export class ProjectList extends PureComponent { static propTypes = { projects: ProjectsType, onPressProject: PropTypes.func } renderItem = ({ item }) => ( <ProjectListItem project={item} onPressProject={this.props.onPressProject} /> ) render() { return ( <FlatList data={this.props.projects} keyExtractor={item => item.id} renderItem={this.renderItem} /> ) } }
Para cada elemento, establecemos una clave única: aquí tenemos la identificación del elemento. Esto es necesario para que la reacción pueda distinguir entre los elementos de la lista y actualizar solo aquellos que han cambiado.
Agregue un componente al elemento de la lista.
export class ProjectListItem extends PureComponent { static propTypes = { project: ProjectType, onPressProject: PropTypes.func } onPressProject = () => { const { project, onPressProject } = this.props onPressProject(project) } render() { return ( <TouchableOpacity onPress={this.onPressProject}> <View style={styles.project}> <Text style={styles.name}>{this.props.project.name}</Text> </View> </TouchableOpacity> ) } }
TouchableOpactity: un contenedor que responde a los clics. Al hacer clic, el componente anidado se vuelve más transparente.
Vista: análogo de div para web: componente básico del marcado.
Texto: un contenedor para texto.
Añadir estilos:
const styles = StyleSheet.create({ project: { paddingVertical: 30, paddingHorizontal: 15, backgroundColor: 'white', borderBottomWidth: StyleSheet.hairlineWidth, borderColor: 'gray' }, name: { fontSize: 16 } })
La sintaxis de estilo se asemeja a CSS, la principal diferencia es que puede estilizar solo el componente en sí (por ejemplo, no puede establecer el tamaño de fuente para toda la aplicación, solo para un componente de texto específico)

Página detallada del proyecto con una lista de notas - Proyecto
Del mismo modo, cree una página detallada. Las diferencias son solo en presencia de un título en el navegador y entrada adicional. En el navegador, establezca el título, el nombre del proyecto. Si no se especifica la identificación del proyecto, le ofreceremos ingresar el nombre del proyecto y crear uno nuevo.
export class Project extends PureComponent { static navigationOptions = ({ navigation }) => { const projectId = navigation.getParam('projectId') return { title: navigation.getParam('name', ''), headerRight: ( <AddButton onPress={() => navigation.navigate('Note', { projectId })} /> ) } } removeNote = noteId => { const { projectId, removeNote } = this.props removeNote(projectId, noteId) } navigateNote = noteId => { const { projectId, navigation } = this.props navigation.navigate('Note', { noteId, projectId }) } createProject = name => { const newProjectId = shortid.generate() this.props.navigation.setParams({ projectId: newProjectId, name }) this.props.addProject(newProjectId, name) } render() { const { projectId, project } = this.props if (!projectId) { return ( <ProjectNameInput onSubmitEditing={this.createProject} /> ) } return ( <NoteList notes={project.notes} onNavigateNote={this.navigateNote} onRemoveNote={this.removeNote} /> ) } }
La página del proyecto es una lista de notas. Según los términos de referencia para cada nota, hay un menú contextual con edición y eliminación. También puede eliminar la nota con un deslizamiento. Hay una lista separada en React Native, con la capacidad de deslizar: SwipeableFlatList.
<SwipeableFlatList data={this.props.notes} bounceFirstRowOnMount={false} keyExtractor={item => item.id} maxSwipeDistance={MAX_SWIPE_DISTANCE} renderQuickActions={this.renderQuickActions} renderItem={this.renderItem} />
Al eliminar una nota, le pediremos confirmación, para esto llamaremos a la alerta estándar del sistema
onRemoveNote = noteId => { Alert.alert( 'Remove Note', 'Do you want to remove note ?', [ { text: 'Cancel', onPress: () => {}}, { text: 'Remove', onPress: () => this.props.onRemoveNote(noteId) } ] ) }

Hay un punto interesante para el menú contextual. A diferencia de la alerta, su implementación en RN para Android e iOS es diferente.
Para Android, use el menú emergente
showPopupMenu = () => { const button = findNodeHandle(this._buttonRef) UIManager.showPopupMenu( button, [ 'Edit', 'Delete' ], e => console.error(e), (e, i) => this.onPressMenu(i) ) }
Para iOS: actionSheet
showActionSheet = () => { ActionSheetIOS.showActionSheetWithOptions({ options: [ 'Edit', 'Delete', 'Cancel' ], destructiveButtonIndex: 1, cancelButtonIndex: 2 }, this.onPressMenu ) }
Hay varias formas de dividir el código específico de la plataforma. Utilizaremos el objeto Plataforma.
onOpenMenu = Platform.select({ android: this.showPopupMenu, ios: this.showActionSheet })

Página de notas detalladas - Nota
La página de notas también es bastante primitiva. Pero, a diferencia de los anteriores, utilizamos el estado para almacenar resultados de entrada de usuario intermedios.
export class Note extends PureComponent { static navigationOptions = ({ navigation }) => ({ headerRight: ( <SaveButton onPress={navigation.getParam('onSaveNote')} /> ) }) state = { noteText: '' } componentDidMount() { this.props.navigation.setParams({ onSaveNote: this.onSaveNote }) } onSaveNote = () => { Keyboard.dismiss() const { projectId, noteId, note, navigation, addNote, editNote } = this.props const { noteText } = this.state if (!noteId) { const newNoteId = shortId.generate() navigation.setParams({ noteId: newNoteId }) addNote(projectId, newNoteId, noteText) } else if (noteText && noteText !== note.text) { editNote(projectId, noteId, noteText) } } onChangeNote = noteText => { this.setState({ noteText }) } render() { const initialTextValue = this.props.note ? this.props.note.text : '' const noteText = this.state.noteText || initialTextValue return ( <NoteDetail noteText={noteText} onChangeNoteText={this.onChangeNote} /> ) } }
La pantalla detallada de la nota, el componente clásico "tonto", informa al alza sobre el cambio de texto y muestra el texto que el padre le pasa.
export class NoteDetail extends PureComponent { static propTypes = { noteText: PropTypes.string, onChangeNoteText: PropTypes.func } render() { const { noteText, onChangeNoteText } = this.props return ( <View style={styles.note}> <TextInput multiline style={styles.noteText} value={noteText} placeholder="Type note text here ..." underlineColorAndroid="transparent" onChangeText={onChangeNoteText} /> </View> ) } }

En total, recibimos la solicitud como en TK. El experimento está completo. El código de la aplicación se puede ver en el
repositorio general
Total, pros y contras de React Native
Pros:
React Native es familiar y comprensible para los desarrolladores familiarizados con React y el marco Node.js y npm. Es posible utilizar todos los enfoques y bibliotecas, como para el React habitual.
Una gran cantidad de paquetes js de npm. Lo más probable es que la mayoría de las tareas estándar ya se hayan resuelto y posiblemente bajo una licencia MIT.
Gran comunidad Tanto los desarrolladores individuales como las grandes empresas han usado RN para el desarrollo y continúan usándolo.
Muchos conjuntos de componentes de interfaz de usuario listos para
usar , como
NativeBase ,
React Native Elements , bibliotecas de grandes empresas como Facebook, Airbnb, Wix.com.
Kit de herramientas claro para el desarrollo conveniente de aplicaciones de Hello World a
Instagram .
Contras:
La aplicación se inicia más lentamente que la nativa y existen algunas dificultades de depuración. El código JS en y sin depurador se ejecuta en diferentes motores. Airbnb escribió muy bien sobre este tema en una
serie de artículos sobre por qué abandonaron React Native en desarrollo.
Dado que el kit de herramientas consta de muchos paquetes que se desarrollan por separado, existe la posibilidad de un conflicto de versión y una interrupción.
No todo se puede hacer sin código nativo. Y cuando realiza cambios en el código nativo, pierde la capacidad de usar Expo y se obliga a construir la aplicación utilizando herramientas de desarrollo nativas estándar.
Muchas gracias a
Mirimon y
HeaTTheatR por invitarme a participar en este experimento. Fue emocionante Por último, agregue un voto.