Saltar al contenido

Objetos profundamente anidados y Redux

¿Por qué no evitar un problema, si podemos verlo venir a kilómetros de distancia? De eso se tratan las mejores prácticas. La documentación de Redux sobre la forma del estado de normalización da una amplia perspectiva sobre el asunto. Sugiere que tratemos el estado de aplicación como una base de datos relacional. Por lo tanto, deberíamos aplicar las prácticas que aplicamos en el diseño de la arquitectura de la base de datos escalable. Veamos el siguiente escenario para entender mejor estas prácticas…

Primero, trataremos de almacenar estos datos en el Formulario de Desglose. Un posible diseño sería el siguiente:

Objetos profundamente anidados y Redux
Objetos profundamente anidados y Redux
12345678910111213141516171819202122232425262728293031323334353637383940{[[ id:1, nombre: "autor 01", posts:[{ título: "Estado de mal rebote", cuerpo:"....", comentarios:[{ userId:10, comentario:"... "}], tags:["react", "redux"] createdFecha:...,}], seguidores:[] createdFecha:...],[ id:2, nombre: "autor 02", posts:[{ título: "Post", cuerpo:".....", comentarios:[...], tags:["react", "redux"] createdFecha:...,}], createdFecha:...],}

javascript

Aunque esto podría parecer una buena arquitectura cuando se ve en forma de objeto, vamos a convertirlo en una mesa y ver si todavía tiene sentido.

12345+----+------+-------------------------------------+-------+--------------+-----------------------------------------+-------------------------+------+ id | nombre | createdDate | post_01_title | post_01_body | post_01_tags | post_01_comment_01_body | post_01_comment_01_user | .... |+----+------+-----------------------------+---------------------------+--------------+-------------------------------------------------+-------------------------+------+ | | | | | |+----+------+-------------------------+---------------------------+--------------------------------+------+---------------------------------+-------------------------+-----------------+------+ 

¡Ahora parece absurdo! Se verá así a menos que normalicemos la tabla y la apliquemos al estado de aplicación. Si estás familiarizado con las reglas de normalización de la base de datos (1NF, 2NF, etc.) puedes aplicar ese conocimiento. Si no, podemos usar algunas reglas básicas para hacer el trabajo. A continuación se muestra el conjunto de directrices del tutorial de Redux sobre esto.

  1. Cada tipo de datos tiene su propia «tabla» en el estado.

Lo primero que hay que hacer es crear una tabla separada para cada tipo de entidad en el escenario. Esto significa que almacenamos los usuarios, los mensajes y los comentarios en tablas separadas. En Redux, esto significaría usar reductores separados (o diferentes secciones en el mismo reductor). Tenga en cuenta que los autores y los usuarios están de hecho en la misma tabla. Además, las etiquetas no están separadas, lo cual es una decisión de diseño que yo elegí. Pero podría ser diferente según las necesidades de la aplicación.

123usuarios :[...]comentarios:[...] posts:[...]

javascript

  1. Cada «tabla de datos» debe almacenar los elementos individuales de un objeto, con los ID de los elementos como claves y los propios elementos como valores.
12345678910111213141516171819202122usuarios:[{"user01":{ id: "user01", nombre: "John Smith",...},...}]posts:[{"post01":{ id: "post01", autor: "user01", título: "Good Redux State", cuerpo:"..."},...}]

javascript

  1. Cualquier referencia a artículos individuales debe hacerse almacenando la identificación del artículo.
  2. Se deben utilizar conjuntos de identificaciones para indicar el pedido.

La última directriz se aplica cuando se necesita un orden específico para el conjunto de objetos. Por ejemplo, los comentarios deben aparecer en un orden que tenga sentido en el hilo.

12345678910111213comments:{ byIds:{{"comment01":{ id: "comment01", comment: "...}, "comment03":{...}, "comment02":{...},}}, allIds:["comment01", "comment02", "comment03",...]}

javascript

En el ejemplo anterior, allIds nos da esencialmente la lista de teclas en orden para que sepamos en qué orden deben ser mostradas. Tenga en cuenta que no necesitamos (y no podemos en los objetos) mantener el orden en los objetos reales.

Siguiendo las pautas anteriores, se obtiene esencialmente un estado de aplicación normalizado que

  1. Simplificar y aplanar el estado (menos posibilidades de estado anidado).
  2. Facilita el acceso a las diferentes propiedades de los objetos.
  3. Aumentar el rendimiento de la interfaz de usuario porque las propiedades de los objetos individuales pueden actualizarse sin tener que actualizar los objetos intermedios.

Pero en un escenario del mundo real, todavía habrá ocurrencias en las que el estado contenga objetos anidados y normalizar más no tiene sentido. En las próximas secciones, exploraremos cómo pueden abordarse estos casos.

Usando Deep Copy

Para esta guía, utilicemos la siguiente estructura de datos hipotéticos que se supone que se almacenan en el estado de aplicación.

123456789101112const initState ={ firstLevel:{ secondLevel:{ thirdLevel:{ property1:..., property2:[...]}, property3:...}, property4:...}}

javascript

También asumimos que esto ya está en la forma más normalizada. Digamos que ahora necesitamos actualizar el valor de la propiedad1 a través de una llamada a la API. Naturalmente, nos inclinaríamos a actualizar directamente los estados, como sigue:

12345678910111213141516/// reducer.jsconst initState ={...}exportfunctionrootLevelReducer(state, action){const nestedState = state.firstLevel.secondLevel. thirdLevel; nestedState.property1= action.data;// esto es similar a// state.firstLevel.secondLevel.thirdLevel.property1 = action.datareturn state;}

javascript

Como he comentado, este cambio no se refleja directamente en el estado. Por lo tanto, Redux no considera una retransmisión del cambio. Nótese que una actualización de la propiedad4 se renderizará ya que hace directamente cambios en el objeto state. Para que se muestre una actualización de la propiedad de un objeto profundamente anidado, es necesario cambiar la referencia de alto nivel. Es decir, es necesario crear una copia profunda del objeto de estado con los cambios deseados en las propiedades anidadas realizadas.

Aunque Object.assign() se ha utilizado para este propósito, hizo que el código fuera en gran parte ilegible. Así llegó el operador Spread.

Con el operador de difusión, podemos simplemente usar la siguiente notación para ejecutar correctamente la actualización de la propiedad.

12345678910111213141516171819const initState ={...}exportfunctionrootLevelReducer(state, action){retorno{...state, firstLevel:{...state. firstLevel, secondLevel:{...state.firstLevel.secondLevel, thirdLevel:{...state.firstLevel.secondLevel.thirdLevel, property1: action.data}}}}

javascript

Aunque esto resuelve nuestro problema de actualizar los objetos profundamente anidados, es evidente que la legibilidad del código cae significativamente. Por lo tanto, trataremos de mejorar la legibilidad utilizando reductores anidados.