Entonces, ¿qué hay de los estados más complejos? Hasta ahora hemos utilizado useState. Y en nuestro ejemplo, volvamos a ese ejemplo. usePerson. Aquí, usar useState está bien, porque no estamos haciendo cosas muy complejas con el estado y no hay mucho de qué preocuparse, ni ninguna razón para complicarlo más. Pero hay casos en los que sí lo necesitarás. Y uno de ellos podría ser cuando comienzas a almacenar múltiples piezas de estado relacionadas, que tal vez no estén completamente relacionadas, como un objeto de persona y algo más, pero están vinculadas entre sí. Y eso podría ser que estés almacenando un objeto personal, pero también quieres almacenar el estado de un formulario, como ¿es válido el formulario? ¿Está sucio el formulario? ¿Ha sido modificado o no? No es parte del objeto de persona, por lo que no debería ir allí, pero de alguna manera pertenece juntos. Un cambio en la persona afectará a ese estado sucio y potencialmente también al estado válido.
Bueno, podrías hacerlo de esta manera, agregando múltiples hooks useState. Y en este caso es relativamente simple, y podríamos salirnos con la nuestra haciéndolo de esa manera. Y podríamos hacer algo como esto, donde la persona, el conjunto de persona o la función que exponemos, en realidad no es la función original de establecimiento de estado de persona, sino una que es un poco más compleja y que cambia múltiples piezas de estado. Funciona. Y en este caso, es lo suficientemente simple como para salirse con la nuestra. Pero si tu escenario se vuelve más complejo, será más difícil mantener esas diferentes piezas de estado y trabajar con ellas. Insights son un componente. Todavía usamos ese mismo use-person. Este set person es una función diferente, una implementación bastante diferente, pero nunca necesita darse cuenta. Y ahora, de repente, obtiene información adicional, como en este caso, está sucio, por lo que podemos deshabilitar el botón de envío, por ejemplo, si el formulario no está sucio y potencialmente si no es válido o algo así. Así que podríamos hacer algo así. Eso está perfectamente bien. Y en realidad vamos a omitir esta parte del laboratorio porque estamos un poco atrasados en el esquema, lo haremos de una manera diferente, y eso es usando useReducer.
Entonces, bajo el capó, useState es en realidad un caso especial de useReducer. Ahora, si piensas en useReducer, espera, he usado Redux que usa reductores, ¿verdad? Bueno, tienes razón, y useReducer es muy similar a usar algo como Redux. No es lo mismo, no es tan poderoso como Redux, pero utiliza exactamente los mismos principios. Y resulta que, si comienzas a mirar el código fuente de React, useState es solo un caso especial con un reductor especial, con otro capó, simplemente llama a useReducer. Entonces, si miras la implementación real de los hooks, no hay un hook real useState, que se administra, es solo un pequeño envoltorio alrededor de useReducer, y useReducer es en realidad el único hook realmente con estado que administra componentes y desencadena re-renderizaciones. Ahora, ¿cómo se usa useReducer? En realidad es bastante simple de usar. Llamas a useReducer con una función reductora. Una función reductora, al igual que con Redux, es una función que toma dos argumentos. El estado actual y la acción actual que se está despachando. ¿Cómo se despacha una función? Bueno, useReducer devuelve una tupla, al igual que useState, excepto que con useState, la segunda función es una función simple que toma un nuevo estado o una función de mutación de estado. En este caso, obtienes una función de despacho y ahí puedes comenzar a despachar acciones. El primer argumento que devuelve, la primera parte de la tupla, sigue siendo el estado actual. Entonces, ya sea useState, useReducer, no importa, sigue siendo el estado actual. Aunque useReducer, ese estado suele ser más complejo, pero no es necesario que lo sea. Y aún está vinculado a un componente. Redux es similar en estructura a Redux, pero Redux es una gestión global de estado que se elimina de tu componente y diferentes componentes pueden compartir el mismo estado suscribiéndose a él mediante useSelector o algo así. Pero con useReducer, todavía está muy vinculado a un solo componente. Si comienzas a usar context y useReducer, en realidad puedes crear una especie de Redux ligero. No lo aconsejaría. Todavía recomendaría usar Redux si quieres hacer eso. Ahora, si quieres hacer eso, lo primero que debes hacer es crear un reductor. Y esta es la primera parte de ese reductor, que es solo un montón de declaraciones que necesitamos. Y la implementación real está aquí. Tenemos una función, PersonEditorReducer. Toma dos parámetros, el estado y la acción. El estado es lo que necesita ser para este useReducer. La acción es típicamente un objeto con un tipo y opcionalmente una carga útil. Por lo general, tiene una carga útil, pero no todas las acciones la necesitan. Y el tipo generalmente decide qué es. Entonces, en este caso, tenemos un tipo de set initial person, que carga un objeto personal, que se almacena en la carga útil. Y tenemos la acción set property, que realmente cambia la persona usando la carga útil, que tiene un nombre y el valor real. Y todo el código en el medio aquí es porque la persona podría ser nula. Entonces, si comenzamos a extender la persona como nula, obtendríamos una persona parcial y TypeScript no le gusta eso. De esta manera, lo solucionamos. Vamos a omitir esto porque en la siguiente parte, vamos a crear otro reductor. No es necesario crear un segundo. Solo voy a explicar esta parte. Dentro de nuestro gancho usePerson o gancho personalizado, en lugar de useState, ahora vamos a usar useReducer y pasamos esa función reductora, que encontramos. Y aquí hay una diferencia con Redux, normalmente configuras tu estado inicial usando la primera llamada al reductor donde el estado es indefinido. En este caso, el segundo argumento para useReducer es en realidad tu estado inicial. Entonces pasamos el objeto. Tiene una persona en ese estado, que por defecto es nulo. Hay un estado de formulario, que por defecto no está sucio y es válido. Entonces, esto configura eso. Devuelve el estado que tiene esta persona en el estado del formulario, y tiene un despacho donde podemos despachar una de esas acciones. Luego, para despachar algo, hacemos algo como esto. En lugar de exportar un objeto setPerson, ahora establecemos, exportamos un setProperty. Y en setProperty, decimos, bueno, queremos despachar algo en este caso, un tipo de setProperty y la carga útil con el nombre y el valor. Y lo mismo sucede, pero eso está un poco fuera de la pantalla ahora, con el despacho setInitialPerson. Ahora, si estás acostumbrado a JavaScript y Redux, es posible que estés acostumbrado a tener creadores de acciones aquí, no despachando objetos como este. Si estás usando JavaScript con useReducer, te recomendaría que hagas exactamente lo mismo. Con TypeScript, realmente no tienes que hacerlo, porque si cometo un error tipográfico aquí en setProperty, en realidad comenzará a quejarse porque el tipo está definido como uno de estos tipos conocidos. Si vuelvo por un segundo aquí con los diferentes tipos, los he establecido ligeramente más abajo. Dos acciones diferentes. Un tipo de setInitialPerson y un tipo de setProperty con su carga útil asociada. Y la acción que espero es una acción setPerson o una acción setProperty. Entonces, si intento despachar un objeto con el tipo, digamos foo, entonces dirá, bueno, foo no es un tipo conocido aquí. Realmente debe ser una de estas dos cadenas exactas. Y una vez que sabe cuál de esas dos es, en realidad conoce la forma de la carga útil. Entonces, si intento despachar setInitialPayload con la forma de la carga útil de setProperty, volveré a obtener un error de compilación de TypeScript que dice, bueno, no coincide. Esa no es una acción adecuada. Debería ser esta forma o esta forma, no alguna combinación o algo más que no coincida con eso. Entonces, TypeScript realmente simplifica casos como ese. Aquí, puedes ver el otro despacho para setInitialPerson. Como dije, vamos a omitir esta parte. En realidad vamos a hacer esto con la segunda parte donde creamos el clon de Foramic. Nuestros componentes han cambiado ligeramente. En lugar de setPerson aquí, obtenemos un setProperty.
Comments