El autor del material, cuya traducción publicamos hoy, dice que es parte del equipo de mensajería
Hike , que se dedica a las nuevas características de la aplicación. El objetivo de este equipo es traducir a la realidad y explorar ideas que les gusten a los usuarios. Esto significa que los desarrolladores deben actuar rápidamente, y que a menudo tienen que hacer cambios en las innovaciones que están investigando, con el objetivo de hacer que la experiencia del usuario sea lo más conveniente y agradable posible. Prefieren realizar sus experimentos con React Native, ya que esta biblioteca acelera el desarrollo y le permite usar el mismo código en diferentes plataformas. Además, usan la biblioteca Redux.

Cuando los desarrolladores de Hike comienzan a trabajar en algo nuevo, cuando discuten la arquitectura de la solución investigada, tienen varias preguntas:
- Esta es una oportunidad experimental que puede, como dicen, "no volar", y tendrá que ser abandonada. Ante esto, ¿es necesario pasar tiempo diseñando la arquitectura de la aplicación?
- Una aplicación experimental es solo un MVP, un producto mínimamente viable que tiene 1-2 pantallas y necesita ser creado lo más rápido posible. Dado esto, ¿debo contactar a Redux?
- ¿Cómo justifica el tiempo que tardan los gerentes de producto en preparar la infraestructura de soporte para una aplicación experimental?
De hecho, Redux lo ayuda a encontrar las respuestas correctas a todas estas preguntas. La arquitectura Redux ayuda a separar el estado de la aplicación de React. Le permite crear un repositorio global ubicado en el nivel superior de la aplicación y proporcionar acceso de estado para todos los demás componentes.
Separación de responsabilidades.
¿Qué es una "separación de responsabilidades"? Esto es lo que
Wikipedia dice al respecto: “En informática, la división de responsabilidades es el proceso de dividir un programa de computadora en bloques funcionales que se superponen las funciones de los demás lo menos posible. En un caso más general, la división de responsabilidades es la simplificación de un solo proceso para resolver un problema dividiéndolo en procesos interactivos para resolver subtareas ".
La arquitectura de Redux le permite implementar el principio de separación de responsabilidades en las aplicaciones, dividiéndolas en cuatro bloques, como se muestra en la siguiente figura.
Arquitectura ReduxAquí hay una breve descripción de estos bloques:
- Las representaciones o los componentes de la interfaz de usuario (Componentes de la IU) se asemejan a funciones puras (es decir, aquellas funciones que no cambian los datos que se les transfieren y tienen algunas otras propiedades) que son responsables de mostrar información en la pantalla en función de los datos transferidos desde la tienda. No cambian los datos directamente. Cuando ocurre un evento, o si el usuario interactúa con ellos, recurren a los creadores de las acciones.
- Los creadores de acciones son responsables de crear y despachar acciones.
- Los reductores reciben acciones programadas y actualizan el estado del repositorio.
- El Data Store es responsable de almacenar los datos de la aplicación.
Considere la arquitectura de Redux como ejemplo.
¿Qué pasa si diferentes componentes necesitan los mismos datos?
La aplicación Hike tiene una pantalla que muestra la lista de amigos del usuario. La información sobre su cantidad se muestra en la parte superior de esta pantalla.
Pantalla de amigos en la aplicación CaminataHay 3 componentes React aquí:
FriendRow
es un componente que contiene el nombre de amigo del usuario y alguna otra información sobre él.FriendsHeader
: un componente que muestra la inscripción "MIS AMIGOS" e información sobre la cantidad de amigos.ContainerView
es un componente contenedor que combina el título de pantalla representado por el componente FriendsHeader
y la lista de amigos obtenidos al atravesar una matriz que contiene información sobre los amigos del usuario, cada elemento del cual se muestra en la pantalla por el componente FriendRow
.
Aquí está el código para
friendsContainer.js para ilustrar lo anterior:
class Container extends React.Component { constructor(props) { super(props); this.state = { friends: [] }; } componentDidMount() { FriendsService.fetchFriends().then((data) => { this.setState({ friends: data }); }); } render() { const { friends } = this.state; return ( <View style={styles.flex}> <FriendsHeader count={friends.length} text='My friends' /> {friends.map((friend) => (<FriendRow {...friend} />)) } </View> ); } }
Una forma completamente obvia de crear una página de aplicación de este tipo es cargar datos sobre amigos en un componente contenedor y pasarlos como propiedades a los componentes secundarios.
Pensemos en el hecho de que esta información sobre amigos puede ser necesaria en algunos otros componentes utilizados en la aplicación.
Caminata en la pantalla de chatSupongamos que la aplicación tiene una pantalla de chat, que también contiene una lista de amigos. Se puede ver que los mismos datos se usan en la pantalla con la lista de amigos y en la pantalla de chat. ¿Qué hacer en una situación similar? Tenemos dos opciones:
- Puede volver a descargar sus datos de amigo en el componente
ComposeChat
responsable de mostrar las listas de chat. Sin embargo, este enfoque no es particularmente bueno, ya que su uso significará la duplicación de datos y puede generar problemas con la sincronización. - Puede descargar datos sobre amigos en un componente de nivel superior (el contenedor principal de la aplicación) y transferir estos datos a los componentes responsables de mostrar una lista de amigos y una lista de chats. Además, necesitamos pasar funciones a estos componentes para actualizar los datos de amigos, lo cual es necesario para admitir la sincronización de datos entre los componentes. Este enfoque conducirá al hecho de que el componente de nivel superior estará literalmente lleno de métodos y datos que no utiliza directamente.
Ambas opciones no son tan atractivas. Ahora veamos cómo se puede resolver nuestro problema utilizando la arquitectura Redux.
Usando Redux
Aquí estamos hablando de organizar el trabajo con datos utilizando almacenamiento, creadores de acciones, reductores y dos componentes de la interfaz de usuario.
▍1. Almacén de datos
El repositorio contiene datos cargados sobre los amigos del usuario. Estos datos se pueden enviar a cualquier componente en caso de que sea necesario allí.
▍2. Creadores de acción
En este caso, el creador de la acción se utiliza para enviar eventos destinados a guardar y actualizar datos sobre amigos. Aquí está el código para
friendsActions.js :
export const onFriendsFetch = (friendsData) => { return { type: 'FRIENDS_FETCHED', payload: friendsData }; };
▍3. Reductores
Los reductores esperan que lleguen los eventos que representan acciones programadas y actualizan a sus amigos. Aquí está el código para
friendsReducer.js :
const INITIAL_STATE = { friends: [], friendsFetched: false }; function(state = INITIAL_STATE, action) { switch(action.type) { case 'FRIENDS_FETCHED': return { ...state, friends: action.payload, friendsFetched: true }; } }
▍4. Componente de listado de amigos
Este componente contenedor visualiza los datos de amigos y actualiza la interfaz cuando cambian. Además, es responsable de descargar datos del repositorio si no los tiene. Aquí está el código para
friendsContainer.js :
class Container extends React.Component { constructor(props) { super(props); } componentDidMount() { if(!this.props.friendsFetched) { FriendsService.fetchFriends().then((data) => { this.props.onFriendsFetch(data); }); } } render() { const { friends } = this.props; return ( <View style={styles.flex}> <FriendsHeader count={friends.length} text='My friends' /> {friends.map((friend) => (<FriendRow {...friend} />)) } </View> ); } } const mapStateToProps = (state) => ({ ...state.friendsReducer }); const mapActionToProps = (dispatch) => ({ onFriendsFetch: (data) => { dispatch(FriendActions.onFriendsFetch(data)); } }); export default connect(mapStateToProps, mapActionToProps)(Container);
▍5. Componente de listado de chat
Este componente contenedor también utiliza datos del almacenamiento y responde a su actualización.
Acerca de la implementación de la arquitectura Redux
Puede llevar uno o dos días llevar la arquitectura descrita anteriormente a condiciones de funcionamiento, pero cuando es necesario realizar cambios en el proyecto, se realizan de manera muy simple y rápida. Si necesita agregar un nuevo componente a la aplicación que utiliza datos sobre amigos, puede hacerlo sin tener que preocuparse por la sincronización de datos o que tendrá que rehacer otros componentes. Lo mismo ocurre con la eliminación de componentes.
Prueba
Cuando se usa Redux, cada bloque de aplicación se puede probar de forma independiente.
Por ejemplo, cada componente de la interfaz de usuario puede someterse fácilmente a pruebas unitarias, ya que es independiente de los datos. El punto es que una función que representa dicho componente siempre devuelve la misma representación para los mismos datos. Esto hace que la aplicación sea predecible y reduce la probabilidad de que ocurran errores durante la visualización de datos.
Cada componente se puede probar exhaustivamente utilizando una variedad de datos. Dichas pruebas revelan problemas ocultos y ayudan a garantizar un código de alta calidad.
Cabe señalar que no solo los componentes responsables de la visualización de datos, sino también los reductores y creadores de acciones pueden ser sometidos a pruebas independientes.
Redux es genial, pero al usar esta tecnología nos encontramos con algunas dificultades.
Dificultades con Redux
▍ Código de plantilla en exceso
Para implementar la arquitectura Redux en una aplicación, debe pasar mucho tiempo, mientras encuentra todo tipo de conceptos y entidades extraños.
Estos son los llamados trineos (thunks), reductores (reductores), acciones (acciones), capas de middleware (middlewares), estas son las funciones
mapStateToProps
y
mapDispatchToProps
, así como mucho más. Toma tiempo aprender todo esto, y para aprender cómo usarlo correctamente, se requiere práctica. Hay muchos archivos en el proyecto y, por ejemplo, un cambio menor en el componente para la visualización de datos puede hacer que sea necesario realizar cambios en cuatro archivos.
La bóveda Redux roja es singleton
En Redux, el almacén de datos se construye utilizando el patrón singleton, aunque los componentes pueden tener múltiples instancias. En la mayoría de los casos, esto no es un problema, pero en ciertas situaciones, este enfoque para el almacenamiento de datos puede crear algunas dificultades. Por ejemplo, imagine que hay dos instancias de un componente. Cuando los datos cambian en cualquiera de estas instancias, esos cambios afectan a otra instancia. En ciertos casos, este comportamiento puede no ser deseable; puede ser necesario que cada instancia del componente use su propia copia de los datos.
Resumen
Recuerde nuestra pregunta principal, que es si vale la pena el tiempo y el esfuerzo para implementar la arquitectura Redux. Nosotros, en respuesta a esta pregunta, decimos Redux "sí". Esta arquitectura ayuda a ahorrar tiempo y esfuerzo en el desarrollo y desarrollo de aplicaciones. El uso de Redux facilita a los programadores realizar cambios frecuentes en la aplicación y facilita las pruebas. Por supuesto, la arquitectura Redux proporciona una cantidad considerable de código repetitivo, pero ayuda a dividir el código en módulos con los que es conveniente trabajar. Cada uno de estos módulos se puede probar independientemente de los demás, lo que ayuda a identificar errores en la etapa de desarrollo y permite garantizar programas de alta calidad.
Estimados lectores! ¿Usas Redux en tus proyectos?
