La gestión del Estado (State
) es una de las partes más importantes de cualquier aplicación Frontend, sea en Qwik o en tecnologías como Angular, React, etc.
Con esto estaremos controlando el flujo de información en tiempo real dentro de nuestra aplicación de manera global, de manera aislada en un componente o mediante la comunicación de ese flujo de información entre diferentes componentes mediante el uso de props
concepto visto anteriormente en el capítulo 3 sobre componentes
u otras formas que iremos viendo en este capítulo.
En este capítulo comenzaremos dando los primeros pasos con las claves para entender como funciona el control de estados y realizaremos casos prácticos para afianzar los conocimientos teóricos.
Esto es lo que vamos a ver en este capítulo:
En Qwik, nos vamos a encontrar con dos tipos de estado:
Estático
: será cualquier cosa que se pueda serializar como por ejemplo una cadena, un número, un objeto, una matriz… cualquier cosa. Esto sería asignar un valor y que se quede sin haber cambios, simplemente visualizar y ya.Reactivo
: se creará haciendo uso de los hooks useSignal()
ó useStore()
. Estos estados se encuentran a la espera de posibles cambios, como podría ser un valor de un contador, la información de respuesta de una llamada a un endpoint de una API, la actualización de la hora, etc.Es importante mencionar que el estado en Qwik no tiene que ser necesariamente el estado a nivel de componente local, sino que podría ser el estado de la aplicación instanciado por cualquier componente.
Una vez realizada la introducción, empezamos a trabajar con las diferentes formas de controlar el estado y empezaremos desde el hook useSignal()
.
Antes de empezar a trabajar nuestro proyecto, dejamos de lado el proyecto anterior llamado 07-ssr y creamos uno nuevo, siguiendo los pasos expuestos anteriormente. Como sugerencia os animo a que lo llaméis 08-state-management-i.
Es un hook que crea una señal reactiva mediante const signal = useSignal(initialState)
, que obtiene un valor inicial (con initialState
) y nos devuelve como resultado una señal reactiva dándonos como resultado un valor que usaremos en la aplicación.
Esto lo usaremos generalmente con valores simples sin mucha complejidad como valores primitivos como strings, enteros,…
Para trabajar con elementos como objetos, es recomendable usar el hook useStore()
, que lo veremos más a fondo en breves.
La señal reactiva devuelta por useSignal()
consiste en un objeto con una sola propiedad (llamada signal.value
). Si cambia la propiedad value del objeto, se actualizará cualquier componente que dependa de él.
useSignal
- Documentación oficial
Aquí tenéis la referencia oficial de useSignal
y accedemos desde el siguiente enlace:
https://shorten-up.vercel.app/L9s2630IVP.
Para implementarlo dentro de un componente, debemos de realizar lo siguiente:
// 1.- importamos useSignal junto con component$
import { component$, useSignal } from '@builder.io/qwik';
// 2.- Inicializamos el estado
export default component$(() => {
const signal = useSignal(<initialState>); // <======
// <initialState> = valor inicial que se asigna
...
});
Por ejemplo, si inicio signalValue
de la siguiente forma:
const signalValue = useSignal(19191);
En este momento el valor de signalValue.value
será 19191
. Si cambia la propiedad value del objeto, se actualizará cualquier componente que dependa de él, pudiendo visualizarlo haciendo simplemente referencia a signalValue.value
Este ejemplo se muestra cómo se puede usar useSignal()
en un componente que mostrará el valor aleatorio siempre que pulsemos el botón con valores comprendidos entre 0 y 1.
import { component$, useSignal } from '@builder.io/qwik';
export default component$(() => {
// Inicia con un valor aleatorio
const randomValue= useSignal(Math.random());
return (
<>
<button onClick$={() => randomValue.value = Math.random()}>Obtener aleatorio</button>
<p>Valor aleatorio actual: {randomValue.value}</p>
</>
);
});
Esto es lo que se consigue con el código que acabamos de implementar:
El simple hecho de acceder a la propiedad randomValue.value
hará que el componente se actualice si cambia el valor de la señal por la reactividad que compone este hook.
En este caso particular se efectúa el cambia en el momento que ejecutamos la acción de click
en el botón con la etiqueta Obtener aleatorio
.
Una vez visto esto, pasamos al siguiente elemento para poder trabajar con la gestión del estado y lo que vamos a usar es el hook useStore()
.
Funciona de forma muy similar a useSignal()
, pero toma un objeto como su valor inicial.
En la práctica, useSignal
y useStore
son muy similares. Este sería el equivalente de los dos:
useSignal(0) === useStore({ value: 0 })
Es preferible el uso de useSignal
para la mayoría de las veces.
Algunos casos de uso para useStore
son:
Para crearlo, lo iniciamos con const store = useStore(initialState)
que es un hook que crea un objeto reactivo, tomando ese objeto inicial y devolviendo un objeto reactivo.
El objeto reactivo devuelto por useStore()
es como cualquier otro objeto, pero es reactivo. Si cambia alguna propiedad del objeto, se actualizará cualquier componente que dependa de esa propiedad.
useStore
- Documentación oficialAquí tenéis la referencia oficial de useStore
y accedemos desde el siguiente enlace:
https://shorten-up.vercel.app/USxY7lllpo.
Este ejemplo muestra cómo se puede usar el hook useStore()
en un componente de contador para realizar un seguimiento del recuento que irá incrementando con la acción de click
del botón asignado a la acción del recuento.
Creamos un componente y añadimos el siguiente código:
...
export default component$(() => {
const counterState = useStore({ count: 0 });
return (
<>
<button onClick$={() => counterState.count++}>+ 1</button>
Count: {counterState.count}
</>
);
});
Esto es lo que tenemos al principio:
El simple hecho de acceder a la propiedad counterState.count
hará que el componente se vaya actualizando a medida que hagamos click en +1. Se verá de la siguiente forma, donde ya se han hecho varios clicks en el botón +1
(exactamente 5).
Seguramente os lo habéis preguntado, ¿Y si no usamos el hook useStore
y añadimos el valor del contador de la siguiente manera const counterState = {count: 0}?
¿Qué pasaría? ¿Actualizaría?
La respuesta es NO, ya que al no usar el hook estamos diciendo que no queremos esperar ningún cambio por lo que si asignamos el valor con 0 por ejemplo, se renderiza con 0 y listo.
Aunque estemos haciendo click en +1
una y otra vez, al no usar el hook useStore
, no vamos a disponer de esa reactividad y no podremos recibir ninguna actualización en los componentes que estemos usando ese valor.
Os invito a que lo probéis y me contáis.
Para iniciar un elemento mediante useStore()
como hemos visto anteriormente, debemos de tener en cuenta la información del objeto inicial a almacenar, que lo pasamos como primer argumento.
Dado que useStore()
tiene una reactividad profunda, esta función se va a encargar de observar al completo en todos los niveles los valores de los arrays y objetos que vayamos almacenando dentro de esta función para almacenar el estado.
Para especificar si queremos observar o no toda la estructura que almacenamos en el useStore()
, debemos de pasar como segundo argumento un objeto con la propiedad deep
(profundidad) en el que asignaremos un valor booleano cuyos valores podrán ser true
o false
.
Por lo tanto, para controlar si la reactividad del elemento almacenado va a ser completa o solo en el nivel superior, iniciamos nuestro useStore()
de la siguiente manera, teniendo en cuenta que vamos a almacenar el siguiente elemento:
{
name: 'Anartz', // Nivel principal (top)
lastName: 'Mugika Ledo', // Nivel principal (top)
otherData: { hobbies: 'wait...' }, // hobbies => Nivel secundario
}
Por defecto, si NO añadimos el valor del segundo argumento va a considerar que quiere especificar el valor { deep: true }
haciendo que observe TODA la estructura.
Sabiendo todo lo anterior, para iniciar el useStore()
con reactividad COMPLETA debemos de realizarlo de la siguiente manera:
const dataStore = useStore({
name: 'Anartz',
lastName: 'Mugika Ledo',
otherData: { hobbies: 'wait...' },
},
{
deep: true
});
O de la siguiente, que será lo mismo a lo anterior, ya que si no añadimos nada, se asigna por defecto el valor { deep: true }
como segundo argumento:
const dataStore = useStore({
name: 'Anartz',
lastName: 'Mugika Ledo',
otherData: { hobbies: 'wait...' },
});
Ahora que ya tenemos claro como activar / desactivar la reactividad completa, vamos a ver su funcionamiento basándonos en que observamos todo, con lo que sería equivalente a { deep: true }
(sin añadirlo).
Usando la base de información anterior, añadimos los cambios en el componente donde estamos trabajando:
import { component$, useStore } from '@builder.io/qwik';
export default component$(() => {
const store = useStore(
{
name: 'Anartz', // Nivel superior (top)
lastName: 'Mugika Ledo', // Nivel superior (top)
otherData: { hobbies: 'wait...' },
// hobbies => NO TOP
},
);
return (
<>
<ul>
<li>
{store.name} {store.lastName} (Esto SI cambia)
</li>
<li>Hobbies: {store.otherData.hobbies} (Esto SI cambia)</li>
</ul>
<button onClick$={() => (store.otherData.hobbies = 'read,sports,music,...')}>
Click me to change hobbies
</button>
<button
onClick$={() => {
store.name = 'Anartz----';
store.lastName = 'Mugika_Ledo';
}}
>
Click me to change Principal
</button>
</>
);
});
Esta será la apariencia:
Probamos las dos opciones:
Click me to change Principal
: Donde cambiaremos el valor de name
y lastName
que se muestran a la vez concatenados.Click me to change hobbies
: Donde cambiaremos el valor de hobbies
que es una propiedad de un objeto dentro de el valor otherData
.El cambio se refleja así:
Esto que acabamos de ver también puede rastrear posibles cambios individuales en los valores individuales dentro de los arrays. ¿Cómo? Ahora lo vemos.
Basándonos en lo que tenemos, pasamos de wait...
a añadir una lista de hobbies
en formato string mediante un array:
import { component$, useStore } from '@builder.io/qwik';
export default component$(() => {
const store = useStore(
{
name: 'Anartz',
lastName: 'Mugika Ledo',
otherData: { hobbies: ['football', 'read', 'music'] }, // <====
}
);
return (
<>
<ul>
<li>
{store.name} {store.lastName} (Esto SI cambia)
</li>
<li>Hobbies: {store.otherData.hobbies.toString()} (Esto SI cambia)</li>
</ul>
<button onClick$={() => (store.otherData.hobbies = ['basket', 'photography', 'write'])}>
Click me to change hobbies
</button>
<button
onClick$={() => {
store.name = 'Anartz----';
store.lastName = 'Mugika_Ledo';
}}
>
Click me to change Principal
</button>
</>
);
});
Ahora tendremos lo siguiente:
Haciendo click en los dos eventos, actualizando tanto los valores de name
+ lastName
como el listado completo dentro de hobbies
:
También podemos reemplazar un elemento del array que estamos usando. Por ejemplo, podríamos cambiar el valor de football
por running
:
import { component$, useStore } from '@builder.io/qwik';
export default component$(() => {
const store = useStore(
{
name: 'Anartz',
lastName: 'Mugika Ledo',
otherData: { hobbies: ['football', 'read', 'music'] }, // <==
}
);
return (
<>
...
<button onClick$={() => (store.otherData.hobbies[0] = 'running')}>
Click me to change hobbies
</button>
...
</>
);
});
Al cargar:
Al actualizar football
por running
(aparte de cambiar el primer elemento):
Incluso se pueden añadir nuevos valores, donde tendremos los 3 iniciales y si hacemos click, añadimos running
, y se hará tantas veces como ejecutemos la acción de click:
...
onClick$={() =>
(store.otherData.hobbies.push('running'))
}
...
Esto será lo que tenemos:
Haciendo click UNA vez:
Haciendo click CUATRO veces:
Después de haber trabajado con la reactividad completa, empezamos a trabajar con el ejemplo DONDE NO VA A FUNCIONAR la actualización del contenido hobbies
debido a que vamos a intentar actualizar una propiedad que no es de nivel superior.
En cambio name
y lastName
si se actualizan debido a que están en el nivel superior.
Para habilitar la opción que solo observe los elementos de nivel superior, como segundo argumento al crear el estado con useStore()
debemos de pasarle el objeto con la propiedad deep
y valor false
:
import { component$, useStore } from '@builder.io/qwik';
export default component$(() => {
const store = useStore({
name: 'Anartz', // (1) - Top Level
lastName: 'Mugika Ledo', // (2) - Top Level
otherData: { hobbies: 'wait...' }, // (3) - Nested Level (No top => hobbies)
},
{
deep: false // <======= Para desactivar el observar completamente
});
return (
<>
<ul>
<li>
{store.name} {store.lastName} (Esto SI cambia)
</li>
<li>
Hobbies: {store.otherData.hobbies} (Esto NO cambia)
</li>
</ul>
<button onClick$={() => (store.otherData.hobbies = 'value change!')}>
Click me to change hobbies
</button>
<button
onClick$={() => {
store.name = 'Anartz----';
store.lastName = 'Mugika_Ledo';
}}
>
Click me to change Principal
</button>
</>
);
});
Esto sería lo que conseguiríamos:
(1)
: Serán los valores que cambian cuando hagamos click en el botón asociado a Click me to change Principal
cuyos valores name
y lastName
concatenados SI se actualizan.
(2)
: En cambio, el apartado de los hobbies
NO se actualiza al hacer click en Click me to change hobbies
por no estar la propiedad dentro del nivel superior ya que es una propiedad hija de otherData
dentro del store.
Al hacer las acciones click, este es el resultado:
Para que las actualizaciones se registren en todos los niveles, debemos de asignarle la estrategia de seguimiento predeterminado que consiste como bien hemos visto en observar TODOS los valores.
Ya sabemos como hacerlo, o añadimos la propiedad deep
y el valor true
como segundo argumento o no añadimos el segundo argumento, pasando de esto:
const store = useStore({
name: 'Anartz', // (1) - Top Level
lastName: 'Mugika Ledo', // (2) - Top Level
otherData: { hobbies: 'not tracked' }, // (3) - Nested Level (No top)
},
{
deep: false
});
A lo siguiente:
const store = useStore({
name: 'Anartz', // (1) - Top Level
lastName: 'Mugika Ledo', // (2) - Top Level
otherData: { hobbies: 'not tracked' }, // (3) - Nested Level (No top)
},
// Podemos ignorar y no poner el segundo argumento
{ deep: true });
Ahora entra en juego la siguiente duda, ¿Es posible pasar estos contenedores de datos a otros componentes?
La respuesta es SI, tanto usando los props
como mediante Context
, que usaremos para un control de estado más global.
Vamos a empezar a implementarlo tanto con useSignal
como useStore
.
Una de las características más interesantes y útiles de Qwik es que el estado se puede pasar a otros componentes, y ambos pueden leerlo y escribirlo, lo que permite que los datos fluyan a través del árbol en todas las direcciones.
Hay dos formas de pasar el estado a otros componentes: con props
o mediante el uso del contexto con Context API
.
La forma más sencilla de pasar el estado a otros componentes es pasarlo como props
.
Esta es la forma en que lo haría en React, y también funciona en Qwik.
Podríamos perfectamente aplicar un ejemplo donde comenzamos asignando un valor inicial numérico mediante useSignal
en un campo de texto y podemos ir cambiando de valor y a su vez se va mostrando los resultados, de por ejemplo una tabla de multiplicación.
Tenemos el componente llamado <Parent>
con el siguiente código:
import { component$, useSignal } from '@builder.io/qwik';
export const Parent = component$(() => {
const multiplyValue = useSignal(1);
return (
<div style="border: 2px solid red; padding: 5px">
<input
value={multiplyValue.value}
onInput$={(ev) =>
(multiplyValue.value = +(ev.target as HTMLInputElement).value)
}
/>
<p>Valor a multiplicar: {multiplyValue.value} </p>
</div>
);
});
En ese componente Parent hemos añadido un nuevo evento.
El evento onInput$ se encarga de detectar los valores introducidos en ese campo. Más detalles sobre los eventos en el Capítulo 14 - Eventos
Esto se vería de la siguiente forma de manera inicial:
Si cambiamos el valor del campo, por ejemplo a 45, el apartado Valor a multiplicar
también cambiará con el valor que tenemos dentro del elemento input:
Ahora lo que nos queda es crear un componente hijo donde vamos a pasar el valor del elemento mediante los props
que usaremos para la tabla de multiplicación y dentro de este mostraremos la tabla de multiplicación hasta 10.
Añadimos lo siguiente a lo actual, creando este componente:
export const Child = (props: any) => {
const { multiplyValue } = props;
return (
<div style="border: 2px solid green">
<p>Tabla de multiplicación: {multiplyValue.value}</p>
<ul>
{Array.from({ length: 10 }).map((_, index) => {
return (
<li>
{multiplyValue.value} * {index + 1} ={' '}
{multiplyValue.value * (index + 1)}
</li>
);
})}
</ul>
</div>
);
};
Y añadimos en la parte inferior la referencia del componente <Child />
junto con el valor que le vamos a pasar mediante los props
de la siguiente forma:
<Child multiplyValue={multiplyValue} />
Y aplicándolo dentro del componente <Parent />
, lo dejamos de esta manera:
import { component$, useSignal } from "@builder.io/qwik";
export default component$(() => {
return <Parent />;
});
export const Child= (props: any) => {
...
};
export const Parent = component$(() => {
const multiplyValue = useSignal(1);
return (
<>
...
<p>Valor a multiplicar: { multiplyValue.value} </p>
<Child multiplyValue={multiplyValue} />
</>
);
});
Y este es el resultado que obtenemos:
Hay que fijarse en los bordes, lo que engloba a lo rojo (1
) es el componente <Parent>
y lo que está en borde verde (2
) es lo correspondiente al componente hijo llamado <Child>
que recibirá el valor de multiplicar y con ello calculará la tabla de multiplicaciones.
Ahora aplicamos mediante el ejemplo trabajado con el useStore
.
Tal y como se ha realizado con el elemento contenedor creado con useSignal
, vamos a pasar la información mediante el uso de props
con useStore
haciendo el ejemplo del contador.
import { component$, useStore } from '@builder.io/qwik';
export default component$(() => {
return <Parent />;
});
export const Parent = component$(() => {
const userData = useStore({
count: 0,
});
return (
<div style="border: 1px solid red; padding: 10px; margin: 5px">
Info in Parent (Counter {userData.count})
<hr/>
<Child userData={userData} />
</div>
);
});
export const Child = component$(({ userData }: any) => {
return (
<div style="border: 1px solid green;margin: 5px">
<button onClick$={() => userData.count++}>+1</button>
Count: {userData.count}
</div>
);
});
Esto sería el estado inicial:
Si realizamos tres click en el botón +1, el valor se tiene que actualizar tanto en el padre (<Parent />
(1
)) como en el hijo (<Child />
(2
)), quedando de la siguiente forma:
El Context API
es una forma de pasar el estado a los componentes sin tener que pasarlo a través de los props
. Automáticamente, todos los componentes descendientes del árbol pueden acceder a una referencia al estado con acceso de lectura/escritura de manera muy sencilla.
Context API
- Documentación oficialAquí tenéis la referencia oficial de Context API
y accedemos desde el siguiente enlace:
https://shorten-up.vercel.app/K5HGMqbnO9.
Lo primero que tenemos que definir es el identificador del contexto que usaremos como referencia:
import {
createContextId, // (A partir de la 0.18.1)
} from '@builder.io/qwik';
export const CONTEXT_ID= createContextId<[TIPO]>(`[IDENTIFICADOR]`);
En nuestro caso como va a ser para almacenar el contador que es un número que cambiará de manera reactiva con useSignal
cuyo tipo será Signal<number>
:
import {
Signal,
createContextId,
} from '@builder.io/qwik';
// TIPO => Signal<number> porque será useSignal(número)
export const CONTEXT_ID = createContextId<Signal<number>>('counter');
Para almacenar el valor usaremos useContextProvider
teniendo en cuenta el identificador del contexto que hemos especificado con CONTEXT_ID
y el valor a almacenar en el estado global de la aplicación, para poder recuperarlo en el componente que deseemos que se reflejará así:
import {
useContextProvider,
} from '@builder.io/qwik';
// Asignamos el valor (state) al contexto (CONTEXT_ID)
useContextProvider(CONTEXT_ID, <VALOR_A_ALMACENAR>);
Aplicándolo en un ejemplo real donde vamos a tener 3 componentes, el primero el padre de todos <First />
y luego su hijo <Second />
y el tercero que será <Third />
, nieto de <First />
e hijo de <Second />
.
import {
Signal,
component$,
createContextId,
useContext,
useContextProvider,
useSignal,
} from '@builder.io/qwik';
export const CONTEXT_ID = createContextId<Signal<number>>('counter');
export const First = component$(() => {
// Creamos el contenedor con el valor del contador
const counterSignal = useSignal(0);
// Asignamos el valor (state = counterSignal) al contexto (CONTEXT_ID)
useContextProvider(CONTEXT_ID, counterSignal);
....
});
Con esto, estaríamos almacenando el valor del estado para poder utilizarlo donde quisiéramos. ¿Cómo obtener el valor estemos donde estemos? Lo único que hay que hacer es usar el hook useContext
y hacer referencia al CONTEXT_ID
que hemos usado para almacenar esa información. En este caso lo haremos así:
const counter = useContext(CONTEXT_ID);
Lo aplicamos con dos componentes, el primero <First />
que será el padre y el segundo, <Second />
que será el hijo del primero:
import {
Signal,
component$,
createContextId,
useContext,
useContextProvider,
useSignal,
} from '@builder.io/qwik';
export const CONTEXT_ID = createContextId<Signal<number>>('counter');
export default component$(() => {
// Creamos el contenedor con el valor del contador
const counterSignal = useSignal(0);
// Asignamos el valor (state = counterSignal) al contexto (CONTEXT_ID)
useContextProvider(CONTEXT_ID, counterSignal);
return (
<div style="border: 1px solid red; padding: 10px; margin: 5px">
Info in Parent (Counter {counterSignal.value})
<hr />
<Second />
</div>
);
});
export const Second = component$(() => {
const counter = useContext(CONTEXT_ID);
return (
<div style="border: 1px solid green;margin: 5px">
Second (Counter) : {counter.value}
<br />
<button onClick$={() => counter.value++}>+ 1</button>
<br />
</div>
);
});
El resultado se refleja de la siguiente forma:
Si hacemos dos veces click, debemos de observar que actualiza en los dos componentes el valor actual del contador cuyo resultado debe de ser dos:
Vamos a hacerlo ahora con un tercer componente que será hijo de <Second />
:
import {
Signal,
component$,
createContextId,
useContext,
useContextProvider,
useSignal,
} from '@builder.io/qwik';
export const CONTEXT_ID = createContextId<Signal<number>>('counter');
export default component$(() => {
// Creamos el contenedor con el valor del contador
const counterSignal = useSignal(0);
// Asignamos el valor (state = counterSignal) al contexto (CONTEXT_ID)
useContextProvider(CONTEXT_ID, counterSignal);
return (
<div style="border: 1px solid red; padding: 10px; margin: 5px">
Info in Parent (Counter {counterSignal.value})
<hr />
<Second />
</div>
);
});
export const Second = component$(() => {
const counter = useContext(CONTEXT_ID);
return (
<div style="border: 1px solid green;margin: 5px">
Second (Counter) : {counter.value}
<br />
<button onClick$={() => counter.value++}>+ 1</button>
<br />
<Third />
</div>
);
});
export const Third = component$(() => {
const counter = useContext(CONTEXT_ID);
return (
<div style="border: 5px solid orange;margin: 5px">
<button onClick$={() => counter.value++}>+1</button>
Count: {counter.value} (Third)
</div>
);
});
Y su resultado es el siguiente, que debe de actualizar en todos ellos el valor del contador cuando hacemos click en el botón de sumar sea en los componentes <Second />
o <Third />
:
Habiendo visto todo lo anterior, ¿Seriáis capaces de hacer la adaptación a useStore
desde useSignal
?
Estoy seguro que si, y sin seguir leyendo, os invito a que intentéis hacerlo. ¿Cuál debería de ser el resultado?
Lo que tenemos que tener en cuenta es el tipo que usamos en createContextId
que en vez de ser Signal<number>
será un tipo genérico como {value: number}
y luego en vez de useSignal
debemos de usar useStore
añadiendo la inicialización de esta manera:
useStore({value: 0})
Visualmente será el mismo resultado y deberá de funcionar de la misma forma, solo que usando el hook useStore
.
El código sería el siguiente:
import {
component$,
createContextId,
useContext,
useContextProvider,
useStore,
} from '@builder.io/qwik';
export const CONTEXT_ID = createContextId<{value: number}>('counter');
export default component$(() => {
// Creamos el contenedor con el valor del contador
const counter = useStore({value: 0});
// Asignamos el valor (state = counter) al contexto (CONTEXT_ID)
useContextProvider(CONTEXT_ID, counter);
(...SIN CAMBIOS)
});
export const Second = component$(() => {
(...SIN CAMBIOS)
});
export const Third = component$(() => {
(...SIN CAMBIOS)
});
El código que encontráis es el resultado final de todo el proceso realizado durante el capítulo en el proyecto 08-state-management-i.
Os recomiendo que vayáis haciendo los pasos poco a poco para ir interiorizando todos los conceptos y en este caso, pienso que os vendría bien realizar pruebas con más ejemplos.
El enlace lo tenéis a continuación:
https://shorten-up.vercel.app/dqBT8fV5k_
Al finalizar este capítulo, deberíamos de ser capaces de:
useSignal
y useStore
con las diferentes opciones.props
y haciendo uso del hook useContext
.Llegados a este punto hemos aprendido un nuevo concepto más, sobre la gestión del estado de la información dentro de los componentes.
Ya estamos cerca de hablar sobre el funcionamiento de los ciclos de vida y como consumir APIs, cuyos conceptos ya nos proporcionarán las herramientas necesarias para poder abordar proyectos de ámbito real.
Finalizamos el capítulo y pasamos al siguiente capítulo donde vamos a seguir trabajando con los estados haciendo uso de otros hooks para trabajar con estados.