1. Introducción a la biblioteca Jotai
La gestión del estado en React es un tema muy discutido con muchas bibliotecas y soluciones. Jotai es una nueva biblioteca basada en átomos, que representan piezas del estado. Forma un gráfico de dependencias para propagar actualizaciones. El concepto es similar a los observables para el flujo de datos asíncronos, pero los átomos tienen algunas diferencias.
Hola a todos. Gracias por la oportunidad de dar esta charla. Espero que la encuentren útil.
Como muchos de ustedes pueden saber, la state management en React es uno de los temas más discutidos en la community. Hay muchas bibliotecas y soluciones. UseStateHook es una de las soluciones primitivas. Algunas de las bibliotecas populares incluyen Redux, MoveX, XState y Zustand. Proporcionan diferentes funcionalidades para diferentes objetivos. Lo bueno es que los desarrolladores tienen muchas opciones para desarrollar sus aplicaciones. Lo malo es que hay demasiadas opciones. Pero creo que tener muchas opciones sigue siendo bueno para el ecosystem. Si solo hubiera una solución, nos perderíamos muchas ideas nuevas.
Jotai es una nueva biblioteca en este campo. Hola, mi nombre es Daishi Kato. Soy el autor de la biblioteca Jotai. Soy medio desarrollador de código abierto y medio freelancer. Mi software de código abierto es con JavaScript y React. Y mi trabajo también está relacionado con JavaScript y React. Hay bastantes proyectos de código abierto en los que estoy trabajando, incluyendo algunos experimentales. Jotai es uno de mis proyectos de código abierto, pero lo desarrollamos como un equipo. Aunque yo soy el principal desarrollador del code, hay muchos contribuyentes, no solo para la codificación, sino también para la documentation y otras cosas.
Esta charla es sobre la biblioteca Jotai, que es una solución para la state management en React. Jotai es una biblioteca basada en átomos, que representan piezas del estado. Los átomos son popularizados por una biblioteca llamada Recoil, pero el concepto no es muy nuevo. El concepto es básicamente formar un gráfico de dependencias de piezas del estado y propagar actualizaciones. Por ejemplo, supongamos que tenemos tres átomos, A, B y C. A depende de B, B depende de C. Si actualizamos C, tanto B como A se actualizan. Este patrón ya se ha hecho, por ejemplo, con observables para el flujo de data asíncrono. Los átomos son un poco diferentes de los observables.
2. Átomos y Gestión del Estado en la Biblioteca Jyotai
Por lo general, los átomos en Jyotai se utilizan para definir el estado sin contener valores. Son como funciones que dependen de otros átomos. Cambiar un átomo desencadena actualizaciones en otros átomos dependientes. El hook UseAtom es similar a useState y devuelve un valor y una función de actualización. Los átomos pueden utilizarse para estados globales, semi-globales o locales.
Por lo general, un objeto observable contendría un valor o tal vez esté inicialmente vacío. Los átomos nunca contendrían valores. Son solo definiciones y los valores existen en otro lugar. Profundizaremos en esto en esta masterclass, pero primero veamos cómo se ve el uso de Jyotai.
Este es un ejemplo sencillo utilizando átomos de Jyotai. Tenemos tres átomos, textAtom, textLengthAtom y uppercaseAtom. textAtom tiene el valor inicial HELLO. textLengthAtom tiene una función que devuelve la longitud de textAtom. uppercaseAtom tiene una función que devuelve de manera similar la cadena de texto de textAtom en mayúsculas. stringAtom y uppercaseAtom ambos dependen de textAtom. Así que si cambias textAtom, los otros dos átomos también cambiarán.
Como puedes ver, si introducimos texto, es decir, si ingresamos un texto en el campo de texto, los tres valores se actualizan en consecuencia. Si observas de cerca, utilizamos el hook useAtom que toma un átomo que hemos definido. El hook UseAtom funciona como el hook useState. Devuelve un valor y una función de actualización. Si el valor cambia, desencadenará un nuevo renderizado. Puedes cambiar el valor con la función de actualización.
Hay una nota importante que no se muestra en este ejemplo. Si utilizamos el mismo átomo, useAtom devuelve el mismo valor. Por lo tanto, podemos usar átomos para el estado global. La biblioteca Jyotai a menudo se considera como una solución de estado global. Podemos usarla para el estado global, pero no es verdaderamente global. Y podemos usarla para estados semi-globales o locales. Esto puede sonar poco intuitivo, pero si piensas en los átomos como funciones, debería tener más sentido. Intentemos hacer una analogía. Todos sabemos que los componentes de React son solo funciones. Este es uno de los componentes más simples. Devuelve una cadena de texto. Por lo general, definimos componentes que devuelven elementos JSX, pero devolver cadenas de texto también es válido. No sabemos exactamente cuándo se invoca esta función.
3. Átomos y Dependencias en la Biblioteca Jotai
React invoca funciones de manera declarativa. Los componentes y los átomos son ambos funciones. Los átomos se utilizan para definir valores estáticos. Para agregar una dependencia, podemos usar el patrón de contexto. Los componentes pueden declarar dependencias, pero no se determina la invocación.
React invocará esta función cuando sea necesario. Es declarativo. Se puede decir que los componentes son funciones declarativas. Sigamos adelante. Los componentes son funciones. Del mismo modo, los átomos son funciones.
Este es un ejemplo similar y es una definición válida de átomo. Tenemos una función de envoltura llamada átomo, pero no es muy importante. Es solo una función útil para construir un objeto AtomConfig, que ayuda especialmente en TypeScript. En este caso, creará un objeto con la propiedad read, que contiene la función. La función es exactamente la misma que vimos en el componente de texto en la anterior diapositiva. Este es un átomo cuyo valor es el valor de retorno de la función, que es una cadena, hola. Es, por así decirlo, un átomo estático cuyo valor nunca cambia.
Un átomo estático no es muy útil, ¿así que cómo añadimos una dependencia? Veamos cómo se ve un componente. Con los componentes de React, hay aproximadamente tres patrones para definir dependencias, props, estados y contexto. Tomemos el contexto como ejemplo, porque es bueno para la analogía. En este ejemplo, creamos un contexto de conteo y definimos un componente doble. El componente doble usará el valor del contexto, lo duplicará y lo devolverá. Siempre que el valor del contexto cambie, esperamos que el componente doble devuelva un valor actualizado. Pero no sabemos cuándo se invocará la función del componente, porque es declarativa. Lo que declaramos es que el componente doble depende del contexto de conteo. Cómo se invoca la función no se determina en este punto. ¿Estás de acuerdo con este ejemplo? ¿Cómo se ve un átomo? Aquí tienes un ejemplo sencillo con átomos.
4. Definiciones de Átomos y Dependencias
Definimos el átomo de conteo y el átomo doble. La función get devolverá el valor de un átomo. El átomo doble depende del átomo de conteo. Cuando definimos átomos, no sabemos cuáles son los valores de los átomos o incluso dónde se almacenan los valores de los átomos. Podemos cambiar las dependencias de los átomos. QuadrupleAtom depende de doubleAtom, y doubleAtom depende de CountAtom. Algunos patrones más son posibles. Por ejemplo, un solo átomo puede depender de varios átomos. Otro ejemplo es que la dependencia del átomo puede ser condicional. Usando estos patrones, podemos definir libremente átomos y hacer un gráfico de dependencia complejo. Básicamente cubrimos cómo definir átomos en términos de leer sus valores. Veamos cómo podemos actualizar los valores.
Definimos el átomo de conteo y el átomo doble. La definición del átomo de conteo es una sintaxis especial que corresponde a crear contexto en el ejemplo anterior. Aprenderemos sobre esta sintaxis un poco más tarde. Hasta ahora, es una definición de átomo que podemos usar desde otros átomos.
A continuación se muestra la definición del átomo doble. Observa una función llamada get. No la definimos. Será inyectada desde algún lugar. La función get devolverá el valor de un átomo. Es como use context devuelve el valor del contexto. El átomo doble depende del átomo de conteo. Y cuando el átomo de conteo cambia, el átomo doble debería ser reevaluado.
Cuando definimos átomos, no sabemos cuáles son los valores de los átomos o incluso dónde se almacenan los valores de los átomos. Lo que sabemos es que cuando se invoca la función, recibirá la función get, y usando la función get, puedes obtener el valor del átomo. Esto es bastante similar a cómo funciona el hook use context. La diferencia es que en los átomos, la función get se inyecta desde el parámetro de la función, mientras que use context se exporta desde la biblioteca react.
Hay otra diferencia. Podemos cambiar las dependencias de los átomos. Definimos un nuevo átomo llamado quadrupleAtom. La función interna devuelve el valor doble de doubleAtom, que es el valor cuádruple del CountAtom original. QuadrupleAtom depende de doubleAtom, y doubleAtom depende de CountAtom. Así que las dependencias están encadenadas. En la práctica, formará un árbol o incluso un gráfico de dependencias. Ahora aprendimos el patrón básico de cómo los átomos forman un gráfico de dependencia simple. Algunos patrones más son posibles. Por ejemplo, un solo átomo puede depender de varios átomos. Otro ejemplo es que la dependencia del átomo puede ser condicional. Usando estos patrones, podemos definir libremente átomos y hacer un gráfico de dependencia complejo. Básicamente cubrimos cómo definir átomos en términos de leer sus valores. Veamos cómo podemos actualizar los valores.
5. Actualización de Valores de Átomos
Para actualizar los valores en Jotai, podemos cambiar la definición de un átomo añadiendo un segundo parámetro. El primer parámetro es la función de lectura, y el segundo parámetro es la función de escritura. La función de escritura tiene tres parámetros: get, set y nuevo valor. Podemos definir estas funciones libremente, lo que permite átomos de solo escritura. Sin embargo, este tema está más allá del alcance de esta masterclass.
Veamos cómo podemos actualizar los valores. Cambiamos la definición del átomo doble añadiendo un segundo parámetro. El primer parámetro se llama función de lectura, y el segundo parámetro se llama función de escritura. Esas funciones simplemente se colocan en las propiedades de lectura y escritura del objeto átomo resultante. La función de escritura tiene tres parámetros, get, set y nuevo valor. En este caso, divide un nuevo valor por 2 y lo establece en el átomo de conteo original. Proporcionar la función de escritura hace que el átomo sea escribible. Las funciones de lectura y escritura de los átomos dobles son simétricas, pero no tienen que serlo. Podemos definir esas funciones libremente. Esto abre un patrón llamado átomos de solo escritura, pero está fuera del alcance de esta masterclass.
6. Definición de Átomo de Cuenta y Átomos Primitivos
La pieza final que falta es la definición del átomo de cuenta. Los átomos primitivos se definen mediante la función de átomo con un solo valor inicial. Son las fuentes de datos en el gráfico de dependencia.
Ahora, la pieza final que falta es la definición del átomo de cuenta en la primera línea. Llamamos a estos átomos, átomos primitivos. Desde la perspectiva del gráfico de dependencia, son las fuentes de data.
Los átomos primitivos se definen mediante la función de átomo con un solo valor inicial. En este caso del átomo de cuenta, cero es el valor inicial. Esta es una sintaxis especial para crear un átomo escribible con un valor inicial. El objeto de configuración de átomo resultante tiene tres propiedades, Init, Read y Write. La propiedad Init tiene el valor inicial. Las funciones Read y Write simplemente leen y escriben al auto-átomo.
Hemos aprendido un átomo normal de solo lectura, un átomo escribible y un átomo primitivo. Los átomos de solo lectura son átomos que se calculan a partir de otros átomos. Los átomos escribibles son átomos de solo lectura más la capacidad de escritura. Los átomos primitivos son átomos escribibles especiales que pueden escribirse a sí mismos. Forman un gráfico de dependencia y los átomos primitivos son la fuente del gráfico.
7. Uso de Átomos con React
Los átomos son puras definiciones de estado que dependen solo de JavaScript. Para usar átomos en React, necesitamos ProviderComponent y UseAtomHook. ProviderComponent almacena los valores de los átomos, mientras que UseAtomHook recupera el valor actual y la función de actualización. Aprender UseAtom es fácil para los desarrolladores familiarizados con UseState. El ejemplo de código muestra cómo cambian los valores de los átomos y se pueden ver en la pantalla. En algunos casos, se puede omitir el Provider, utilizando el estado global para los valores de los átomos. Sin embargo, en otros casos se pueden usar múltiples Providers.
Al principio de esta masterclass, presenté a Jotai como una solución de state management para React. Como vimos cómo construir átomos, no tienen nada que ver con React. Los átomos son puras definiciones de estado que dependen solo de JavaScript. La función de átomo puede parecer mágica, pero es solo una función auxiliar para hacer un objeto de configuración. Técnicamente, podrías definir el objeto de átomo sin usar la función auxiliar.
Entonces, si los átomos no son cosas de React, ¿cómo podemos usarlos con React? Para usar átomos en React necesitamos dos funciones. Una es ProviderComponent. La otra es UseAtomHook. Como sigo diciendo, los objetos de átomo son solo definiciones y no contienen valores. Por lo tanto, necesitamos un lugar para almacenar los valores de los átomos. Ese es el ProviderComponent. Tiene los valores de todos los átomos bajo el árbol de componentes. Para usar un valor de átomo en el ProviderComponent, usamos UseAtomHook en el componente hijo. Toma un objeto de átomo y devuelve el valor actual en el ProviderComponent y la función de actualización para cambiar el valor en el Provider. El uso de UseAtom es similar a UseState y UseReducer. Por lo tanto, aprender UseAtom es casi nada para los desarrolladores que ya están familiarizados con UseState.
Veamos el mismo ejemplo que vimos antes. TextAtom es un átomo primitivo, y los otros dos átomos son átomos de solo lectura. Dependen de TextAtoms. Entonces, cuando cambia el valor de TextAtom, cambian los valores de los tres átomos, y las actualizaciones se pueden ver en la pantalla. El code en la diapositiva no muestra el componente Provider, pero está allí en la parte inferior. Sin embargo, en algunos casos, podemos omitir el Provider. Para muchos casos de uso, tendríamos un Provider cerca de la raíz del árbol de componentes. Si solo hay un Provider en la memoria, podemos omitirlo. Luego utiliza un estado global para los valores de los átomos. Es una característica muy útil y a menudo utilizada. Si nunca tenemos un componente Provider, teóricamente los átomos pueden contener valores. Entonces, ¿cuál es el punto de separar los átomos y los valores? Acabo de decir que si hay un Provider en la memoria, podemos omitirlo. Eso significa que en otros casos, tener múltiples Providers es significativo y es posible si los átomos no contienen valores. Este es un ejemplo con dos Providers.
8. Átomos en la Biblioteca Jotai y Bibliotecas Experimentales
Los átomos en Jotai son definiciones reutilizables que son independientes de React. Se pueden utilizar sin React en una biblioteca experimental llamada Jotajsx. JotaiSignal y JotaiUncontrolled son otras dos bibliotecas experimentales. Los átomos de Jotai son definiciones de estado agnósticas al marco de trabajo. Para los usuarios existentes de Jotai, recuerden que los átomos son como funciones. Se anima a los nuevos usuarios a probar la biblioteca Jotai.
Observa que tenemos un átomo definido, que es CountAtom. El componente Counter también está definido una vez. Ahora usamos el componente Counter en dos Providers. Como esos dos Providers tienen diferentes valores de átomo, vemos dos valores diferentes en pantalla. Veamos cómo funciona. Los Counts están separados. Hacer clic en ambos extremos solo afecta al Count en un Provider. Esto es lo que quiero decir. La definición de átomo es reutilizable, es como una función.
Hay otro caso en el que los átomos no deben contener valores. En el contexto del servidor, hay múltiples solicitudes y cada solicitud inicia una nueva renderización. Necesitamos un componente Provider para cada renderización para aislar los estados entre las solicitudes. Las definiciones de átomo pueden compartirse entre solicitudes, pero los valores de átomo no. Esto es realmente hipotético porque en este momento básicamente no hay forma de actualizar los valores de átomo en el servidor. Dicho esto, se siente bien separar la definición y los valores si manejamos múltiples cosas en un solo espacio de memoria. Y podríamos hacer más cosas en el servidor en el futuro.
Entonces, si los átomos son solo definiciones e independientes de React, ¿podemos usarlos sin React? Para responder a esa pregunta, hice una biblioteca experimental llamada Jotajsx. Es una biblioteca que técnicamente reemplaza las bibliotecas de React y React-dom, ya que la sintaxis es exactamente la misma que el uso normal de Jotai con React. Podemos ejecutar una aplicación Jotai solo cambiando las líneas de importación. No está completa en características y puede contener errores, pero muestra una prueba de concepto. Las otras dos bibliotecas experimentales se llaman JotaiSignal y JotaiUncontrolled. Básicamente funcionan con React, pero la sintaxis es diferente. Una es de estilo signal y la otra es para componentes no controlados. Sus implementaciones vienen con hacks, pero también deberían mostrar la prueba del concepto de Átomo. En el futuro, la biblioteca Jotai eventualmente expondrá funciones vanilla que no están atadas a React. Y podríamos construir más bibliotecas en nuestro ecosistema. Estas tres bibliotecas están alojadas bajo la organización de GitHub llamada jotailabs. Allí esperamos mejorar las bibliotecas para uso práctico y agregar más bibliotecas para experimentos.
En resumen, la conclusión es la siguiente. Los átomos de Jotai son como funciones. Y son definiciones de estado agnósticas al marco de trabajo. Si ya eres usuarios de Jotai, por favor intenta tener eso en mente, lo cual puede ayudar a diseñar átomos. Si eres nuevo en la biblioteca Jotai, por favor pruébala. Tenemos un sitio web en jotai.org y hay algunas documentaciones. Esperamos comunicarnos con los usuarios y contribuyentes. Este es el final de mi charla. Gracias.
Comments