Uso Vanilla JS para páginas web interactivas y estoy tratando de entender si mi patrón de diseño está implementando correctamente el principio de reactividad.
(Nota: no me refiero a la biblioteca React, aunque estoy feliz de que las respuestas se basen en características o estrategias de dichas bibliotecas).
Mi entendimiento básico es que tiene algunos datos que actúan como su única fuente de verdad, escucha los cambios y cuando esos datos cambian, su página | aplicación | componente se vuelve a renderizar para reflejar eso.
Aquí hay una versión simplificada de lo que hago, con preguntas después.
Digamos que tengo mi única fuente de verdad:
let data = {} data.someContent = 'Hello World' data.color = 'red'y el marcado de mi aplicación en una cadena de plantilla para la representación dinámica:
function template(data) { return ` <div id="app" style="color:${data.color}">${data.someContent}</div> ` } // assume there are also plain HTML inputs on the page, outside of what gets re-rendered.una función que renderiza en base a los datos:
function render(data) { document.getElementById('app').innerHtml = template(data) }luego, por el equivalente de la reactividad de las actualizaciones del lado del cliente:
document.addEventListener('input', (e) => { data[e.target.id] = e.target.value // update data to reflect input render(data) // re-render based on new data })y de las actualizaciones del lado del servidor:
function fetchDataAndReRender() { data.propToUpdate = // fetch data from server render(data) // again, re-render return }Por lo tanto, tenemos la única fuente de verdad y renderizado basado en actualizaciones de datos.
data , por ejemplo, a través de Proxies. Parece que la única ventaja es evitar llamar manualmente a render() . ¿Es eso correcto?--
EDITAR: agregar un enlace a una publicación de blog que imita la estrategia reactiva vainilla anterior: https://css-tricks.com/reactive-uis-vanillajs-part-1-pure-funcional-style/ Hay algunas variaciones menores, pero sirve como un buen punto de referencia para cualquier persona interesada en este estilo.
Lo principal que me falta aquí es una forma de optimizar las re-renderizaciones.
Interactuar con el DOM es costoso, por lo que además de usar un Proxy alrededor de sus datos/estado para llamar automáticamente a render , lo ideal sería evitar simplemente reemplazar todo el HTML de su aplicación si solo un elemento o, digamos, un atributo ha cambiado. :
Considere actualizar un <input> . Si no puede detectar que solo su valor ha cambiado y actualizarlo, y en su lugar reemplaza todo el HTML que incluye esta entrada, el cursor se moverá al final después de cada renderizado (probablemente después de cada carácter que escriba) .
Considere una función de arrastrar y soltar. Si no puede detectar que el usuario está arrastrando algo por la pantalla y solo actualiza la propiedad de transform CSS en él, y en su lugar reemplaza todo el HTML que incluye el elemento que se está arrastrando, el rendimiento será horrible. Además, interrumpirá los eventos de arrastre, por lo que esto no funcionará en absoluto.
Otra posible optimización sería realizar actualizaciones por lotes, por lo que si actualiza sus datos 3 veces seguidas, podría actualizar el HTML solo una vez con el resultado final. Ya mencionaste que eliminas eventos de entrada continuos, que sería una forma de hacerlo.
Respuestas a sus comentarios:
(1) Asumí que quería una solución de propósito general, ahí es donde es imprescindible poder detectar cambios y solo actualizar las partes del DOM que necesitan ser actualizadas.
Si solo necesita (re) renderizar pequeños fragmentos estáticos de HTML, entonces probablemente pueda prescindir de esto. Las dos razones principales son:
Como dijiste, no hay interactividad, por lo que no experimentarás los problemas que ejemplifiqué.
Como sus actualizaciones son pequeñas, es poco probable que vea problemas de rendimiento al reemplazar bloques de HTML en lugar de intentar actualizar los elementos existentes en el DOM.
(2) En cualquier caso, el principal problema al que te tendrías que enfrentar si tratas de actualizar solo lo que ha cambiado no sería encontrar los datos que han cambiado (independientemente de si usas un Proxy o no), sino mapear eso a la elementos que necesitan ser actualizados y acciones que realizarían esas actualizaciones.
(3) También puede hacer compromisos en el lado de la aplicación, por ejemplo, que los datos deben ser inmutables (como con React).
Esta no es una respuesta a su pregunta. Es un comentario demasiado largo para caber en el espacio de comentarios.
Qué significa "pensamiento reactivo", al menos en mi opinión
"pensar de forma reactiva" significa, hasta donde puedo decir, que modela su problema en términos de "flujos de eventos" y los "efectos secundarios" que tienen tales eventos, por ejemplo, lo que sucede en su pantalla cuando ocurren algunos de estos eventos.
En una aplicación front-end, el primer evento es "alguien abre la aplicación" y el efecto secundario es que "ves algo en tu pantalla", generalmente el navegador.
Luego, a partir de ese evento, cambia a otro flujo de eventos, o probablemente a la combinación de muchos flujos de eventos.
Esta combinación puede ser la combinación de:
Cada uno de estos flujos de eventos tiene sus propios efectos secundarios:
El resumen es que, en estilo reactivo, escribes el libro de "qué sucede cuando" y luego despliegas este libro.
En términos más precisos, puede declarar cómo se comportará una aplicación completa como un único flujo de eventos y los efectos secundarios relacionados.
Una vez que su declaración esté completa (y correcta), simplemente suscríbase a la transmisión y deje que fluyan los eventos y sus efectos secundarios.
¿Vale la pena programar de esta manera hasta el extremo? Probablemente no, como todas las posiciones extremas.
¿Es conveniente algunas veces? Definitivamente sí.