Om pero en javascript


Me estoy volviendo fan de la biblioteca Om de David Nolen .

Quiero construir una aplicación web no demasiado grande en nuestro equipo, pero realmente no puedo convencer a mis compañeros de equipo para cambiar a ClojureScript.

¿Hay alguna forma en que pueda usar los principios utilizados en om pero compilar la aplicación en JavaScript?

Estoy pensando algo como:

  1. inmutable-js o mori para estructuras de datos inmutables
  2. js-csp para CSP
  3. solo un objeto javascript normal para la aplicación-state atom
  4. inmutable-js para cursores
  5. algo para hacer un seguimiento del estado de la aplicación y enviar la base de notificaciones en los cursores

Estoy luchando con el número 5 anterior.

¿Alguien se ha aventurado en este territorio o tiene alguna sugerencia? Tal vez alguien ha intentado construir una reacción.aplicación js usando inmutable-js?

 41
Author: Ruben Bartelink, 2014-09-11

2 answers

Editar Julio 2015 : actualmente el marco más prometedor basado en la inmutabilidad es Redux ! echa un vistazo! No usa cursores como Om (ni Om Next usa cursores).

Los cursores no son realmente escalables, a pesar de usar los principios de CQRS descritos a continuación, todavía crea demasiada repetición en los componentes, que es difícil de mantener, y agrega fricción cuando desea mover componentes en una aplicación existente.

Además, no está claro para muchos devs on when to use and not use cursors, and I see devs using cursors in place they should not be used, making the components less reusable that components taking simple props.

Redux usa connect(), y explica claramente cuándo usarlo (componentes contenedores), y cuándo no (componentes sin estado/reutilizables). Resuelve el problema repetitivo de pasar cursores por el árbol, y funciona mucho sin demasiados compromisos.

He escrito sobre los inconvenientes de no usar connect() aquí

A pesar de no usar más cursores, la mayor parte de mi respuesta sigue siendo válida en mi humilde opinión


Lo he hecho yo mismo en nuestro marco interno de inicio atom-react

Algunas alternativas en JS son Morearty, Reaccionar-cursores, Omnisciente o Baobab

En ese momento no había immutable-js todavía y no hice la migración, todavía usando objetos JS simples (congelados).

I no piense que el uso de una lib de estructuras de datos persistentes es realmente necesario a menos que tenga listas muy grandes que modifique/copie a menudo. Puede usar estos proyectos cuando note problemas de rendimiento como una optimización, pero no parece ser necesario implementar los conceptos del Om para aprovechar shouldComponentUpdate. Una cosa que puede ser interesante es la parte de immutable-js acerca de las mutaciones por lotes. Pero de todos modos todavía creo que es la optimización y no es un requisito básico para tener un rendimiento muy decente con Reaccionar usando los conceptos de Om.

Puede encontrar nuestro código opensource aquí:

Tiene el concepto de un átomo Clojurescript que es una referencia intercambiable a un objeto inmutable (congelado con DeepFreeze). También tiene el concepto de transacción, en caso de que desee que varias partes del estado se actualicen atómicamente. Y puede escuchar los cambios Atom (fin de la transacción) para activar el renderizado React.

Tiene el concepto de cursor , como en Om (como una lente funcional). Permite que los componentes puedan representar el estado, pero también modificarlo fácilmente. Esto es útil para formularios, ya que puede vincular a cursores directamente para el enlace de datos de 2 vías:

<input type="text" valueLink={this.linkCursor(myCursor)}/>

Tiene el concepto de pure render, optimizado fuera de la caja , como en Om


Diferencias con Om:

  • Ningún estado local (esto.setState(o) forbidden)

En los componentes Atom-React, no se puede tener un estado del componente. Todo el estado se almacena fuera de React. A menos que tenga necesidades de integración de bibliotecas Js existentes (aún puede usar clases React regulares), almacena todo el estado en el Átomo (incluso para valores asincrónicos/de carga) y toda la aplicación se vuelve a reenviar desde el componente principal de React. React es entonces solo un motor de plantillas, muy eficiente, que transforma un estado JSON en DOM. Encuentro esto muy útil porque puedo registrar el estado Atom actual en cada renderizado, y luego depurar el código de renderizado es muy fácil. Gracias a out of the box shouldComponentUpdate es lo suficientemente rápido, que incluso puedo volver a leer la aplicación completa cada vez que un usuario presiona una nueva tecla del teclado en una entrada de texto, o pasa el ratón por un botón. Incluso en un teléfono móvil!

  • Forma obstinada de administrar el estado (inspirada en CQRS/EventSourcing y Flux)

Atom-React tiene una manera muy obstinada de manejar el estado inspirado por Flux y CQRS. Una vez que tengas todo su estado fuera de React, y tiene una manera eficiente de transformar ese estado JSON en DOM, descubrirá que la dificultad restante es administrar su estado JSON.

Algunas de estas dificultades encontradas son:

  1. Cómo manejar valores asíncronos
  2. Cómo manejar efectos visuales que requieren cambios DOM (mouse hover o focus por ejemplo)
  3. Cómo organizar su estado para que se escale en un equipo grande
  4. Donde disparar el ajax peticiones.

Así que termino con la noción de Tienda, inspirada en la arquitectura de Flujo de Facebook. El punto es que realmente no me gusta el hecho de que una tienda de flujo pueda depender de otra, lo que requiere orquestar acciones a través de un despachador complejo. Y terminas teniendo que entender el estado de múltiples tiendas para poder renderizarlas.

En Atom-React, la Tienda es solo un "espacio de nombres reservado" dentro del estado Atom.

Así que prefiero que todas las tiendas se actualicen desde un flujo de eventos de lo que sucedió en la aplicación. Cada almacén es independiente y no accede a los datos de otros almacenes (exactamente como en una arquitectura CQRS, donde los componentes reciben exactamente los mismos eventos, se alojan en diferentes máquinas y administran su propio estado como quieren). Esto hace que sea más fácil de mantener, ya que cuando está desarrollando un nuevo componente solo tiene que entender el estado de una tienda. Este de alguna manera conduce a la duplicación de datos porque ahora varias tiendas pueden tener que mantener los mismos datos en algunos casos (por ejemplo, en un SPA, es probable que desee el ID de usuario actual en muchos lugares de su aplicación). Pero si 2 tiendas ponen el mismo objeto en su estado (procedente de un evento), esto en realidad no consume ningún dato adicional, ya que sigue siendo 1 objeto, al que se hace referencia dos veces en las 2 tiendas diferentes.

Para entender las razones detrás de esta elección, puede leer las publicaciones del blog del líder de CQRS Udi Dahan, La Falacia De La Reutilización y otros sobre Componentes Autónomos.

Por lo tanto, un almacén es solo una pieza de código que recibe eventos y actualiza su estado de espacio de nombres en el Átomo.

Esto traslada la complejidad de la gestión de estado a otra capa. Ahora lo más difícil es definir con precisión cuáles son los eventos de su aplicación.


Tenga en cuenta que este proyecto sigue siendo muy inestable e indocumentado/no está bien probado. Pero ya lo usamos aquí con gran éxito. Si quieres discutirlo o contribuir, puedes contactarme en IRC: Sebastien-L en #reactjs.

Esto es lo que se siente al desarrollar un SPA con este marco. Cada vez que se procesa, con el modo de depuración, tiene:

  • El tiempo que tomó transformar el JSON en DOM Virtual y aplicarlo al DOM real.
  • El estado registrado para ayudarlo a depurar su aplicación
  • tiempo perdido gracias a React.addons.Perf
  • Una diferencia de ruta en comparación con el estado anterior para saber fácilmente qué ha cambiado

Compruebe esta captura de pantalla:

introduzca la descripción de la imagen aquí

Algunas ventajas que este tipo de marco puede traer que no he explorado tanto todavía:

  • Realmente tienes deshacer / rehacer incorporado (esto funcionó fuera de la caja en mi aplicación de producción real, no solo un TodoMVC). Sin embargo, en mi humilde opinión, la mayoría de las acciones en muchas aplicaciones están produciendo efectos secundarios en un servidor, por lo que no siempre hace sentido revertir la interfaz de usuario a un estado anterior, ya que el anterior estado sería rancio

  • Puede grabar instantáneas de estado y cargarlas en otro navegador. CircleCI ha mostrado esto en acción en este video

  • Puede grabar "videos" de sesiones de usuario en formato JSON, enviarlos a su servidor backend para depurar o reproducir el video. Puede transmitir en vivo una sesión de usuario a otro navegador para obtener asistencia del usuario (o espiar para verificar el comportamiento de UX en vivo de sus usuarios). Los estados de envío pueden ser bastante caros, pero probablemente formatos como Avro pueden ayudar. O si la transmisión de eventos de su aplicación es serializable, simplemente puede transmitir esos eventos. Ya lo implementé fácilmente en el framework y funciona en mi aplicación de producción (solo por diversión, aún no transmite nada al backend)

  • La depuración que viaja en el tiempo ca será posible como en ELM

He hecho un video de la función "grabar sesión de usuario en JSON" para aquellos interesados.

 59
Author: Sebastien Lorber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:18

Puede tener un estado de aplicación como Om sin otro envoltorio React y con flujo puro: compruébelo aquí https://github.com/steida/este Ese es mi kit de inicio React muy completo.

 3
Author: Daniel Steigerwald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-23 22:25:06