¿Cómo migrar de UseState a UseReducer para CustomHooks en React?
La migración de UseState a UseReducer puede parecer desafiante, pero es esencial para mejorar la gestión de estados en aplicaciones complejas. En este ejemplo práctico, te mostramos cómo aplicar este cambio en un CustomHook en React, aprovechando al máximo tus habilidades en desarrollo. ¡Empecemos!
¿Qué es un CustomHook y por qué es importante mantener su estructura?
Un CustomHook es una función en React que permite reutilizar lógica de estado y efectos entre varios componentes. En este caso específico, estamos trabajando con UseLocalStorage, que gestiona la lógica del almacenamiento local y se utiliza en otros hooks o componentes como UseToDo.
Mantener la estructura del CustomHook es crucial. Imagina que muchas personas dependen de dicho hook en su proyecto. Cualquier cambio que rompa la funcionalidad podría afectar significativamente a quienes lo utilizan, haciendo esencial asegurarse de que los parámetros de entrada y salida permanezcan inalterados.
¿Cómo se define el initial state y el reducer en UseReducer?
Para comenzar, necesitamos definir un initial state que refleje el estado inicial de nuestra aplicación componente. En el caso de UseLocalStorage, esto podría incluir valores como SynchronizeItem o Loading, establecidos según los valores iniciales de nuestra lógica.
const initialState ={synchronizeItem:true,error:false,loading:true,item: initialValue // este valor se deriva del parámetro de entrada};
El siguiente paso es crear un reducer sólido. Este reducer debe manejar múltiples tipos de acción que reflejan el ciclo de vida de nuestra lógica, facilitando la transición entre diferentes estados. Al definir estos types, nos aseguramos de que nuestro código sea escalable y legible.
¿Cómo se implementan los ActionCreators y ActionTypes?
Implementar ActionCreators y ActionTypes es clave para una migración efectiva. Los ActionCreators encapsulan la lógica para la creación de acciones, lo que simplifica la gestión de las mismas a lo largo de tu aplicación.
Con estos ActionCreators, la lógica de las acciones está centralizada, lo que facilita el mantenimiento y el escalado del código. Además, garantiza que las acciones sean coherentes y se gestionen de manera uniforme.
¿Por qué es importante seguir un flujo de desarrollo sistemático?
Durante un proceso de migración, es probable que aparezcan errores o inconvenientes. A lo largo del código, es prioritario verificar cada parte del flujo, asegurando que los datos se transmitan correctamente entre estados. Un error común es olvidar actualizar un ActionType o ActionCreator, lo que puede resultar en que el flujo se detenga inesperadamente.
Mantener buenas prácticas como comentar partes críticas del código, probar cada interacción y validar resultados, son tácticas que nos ayudan a identificar rápidamente los puntos débiles y a resolver problemas antes de que escalen.
¡No te desanimes si encuentras algún error! La práctica constante y el análisis de resultados mejorarán tu habilidad para migrar y gestionar estados en React, llevándote a un nivel más profesional.
¡Sigue creciendo y aprendiendo! Cada paso te acerca más a ser un experto en React.
Me parece gracioso que el profesor sepa muchas cosas pero no se acuerde de como se llaman los símbolos () {} [] jaja pero es todo un crack el profe, mis respetos!
Quizá no los nombre a propósito ya que hay gente que los nombra de diferente manera y para no generar conflicto con los alumnos no se inclina por ningún nombre en particular
O quizás simplemente no se acuerde (?
Justamente, tiene su memoria llena de cosas importantes y deja de lado las cosas insignificantes :bulb:
Código de la clase por si te pierdes o te da pereza:
👍 Like si te diste cuenta que faltaba el SAVE, y pensaste en cómo le digo a JuanDC que faltaba el SAVE!!!!! 😬
Literalmente le empece a hablar a la pantalla xD
Sincronized (pasado)
Sincronize (verbo)
Sincronizada (mi desayuno)
Nooooooooooo
¡No tenía idea que sincronizada también era una quesadilla jajajaja!
Siii, ahí cuando vengas a México te puedes pedir una en cualquier taquería, aunque también se conocen como gringas xd
La redundancia del minuto 18:15 podemos solucionarla de la siguiente manera:
En el return decimos que sincronizeItem es igual a nuestra función onSincronize.
Ahora ya podemos eliminar la función sincronizeItem.
De esa manera mantenemos la estructura del return y nos ahorramos código redundante.
como creas este tipo de imagenes?
lo mismo pense :)
Me acabo de dar cuenta que "sincronize" se escribe "sycronize". El IDE me mostró la correción del diccionario Jeje ¡Igual el profesor es un crack!
Según Google sería synchronize
Pase más de 1h y media con un error, debugueando y debugueando, al final, era que en mi función onSuccess, escribí "paylaod" en vez de "payload".
Quería dejar la anécdota jajajaja
Que shortcut utiliza para escoger colocar el cursor al inicio de la palabra y después seleccionar exclusivamente esa palabra? Minuto 2:25
En Windows es Ctrl + Shift + flechita de izquierda o derecha.
En macOS es option + shift + flechita de izquierda o derecha.
Esta es sin duda la clase mejor clase del curso!
Los conceptos más importantes fueron aplicados de manera excelente con un ritmo perfecto!
Entendí todito :D
💚 Gracias Platzi.
Si como yo prefieres usar reducer con un switch, acá te dejo mi código 😁
importReact,{ useEffect }from'react';functionuseLocalStorage(itemName, initialItemValue){const[state, dispatch]=React.useReducer( reducer,initialState({ initialItemValue }));const{ error, sincronizedItem, loading, item }= state;// ACTION CREATORSconstonError=(error)=>{dispatch({type: actionTypes.error,payload: error });};constonSuccess=(item)=>{dispatch({type: actionTypes.success,payload: item });};constonSave=(item)=>{dispatch({type: actionTypes.save,payload: item });};constonSincronize=()=>{dispatch({type: actionTypes.sincronize});};useEffect(()=>{setTimeout(()=>{try{let parsedItem;const localStorageItem =localStorage.getItem(itemName);if(!localStorageItem){localStorage.setItem(itemName,JSON.stringify(initialItemValue)); parsedItem = initialItemValue;}else{ parsedItem =JSON.parse(localStorageItem);}onSuccess(parsedItem);// setItem(parsedItem);// setLoading(false);// setSincronizedItem(true);}catch(error){onError(error);}},1000);},[sincronizedItem]);/* function that help us to save the item at the state and also localStorage */constsaveItem=(newItem)=>{try{const stringifiedItem =JSON.stringify(newItem);localStorage.setItem(itemName, stringifiedItem);onSave(newItem);}catch(error){onError(error);}};constsincronizeItem=()=>{onSincronize();};/* we return the item that is the main thing that we wont save on localStorage, and saveItem, the function to actualize the state and localStorage */return{ item, saveItem, loading, error, sincronizeItem,};}constinitialState=({ initialItemValue })=>({error:false,sincronizedItem:true,loading:true,item: initialItemValue,});const actionTypes ={error:'ERROR',success:'SUCCESS',save:'SAVE',sincronize:'SINCRONIZE',};constreducer=(state, action)=>{switch(action.type){case actionTypes.error:return{...state,error:true,};case actionTypes.success:return{...state,error:false,loading:false,sincronizedItem:true,item: action.payload,};case actionTypes.save:return{...state,item: action.payload,};case actionTypes.sincronize:return{...state,Loading:true,sincronizedItem:false,};default:break;}};export{ useLocalStorage };
sync
Hola muy buenas, por lo que he visto a lo largo del curso es mejor manejar el estado entero de la aplicación de una más general y centrada en un solo lugar, para eso se usan herramientas como redux y apollo, mi pregunta es, esto debe ser así todo el tiempo ? Y cuándo sería la mejor opción para usar una o otra manera ?
Hola Danny, no, no todo el tiempo es recomendado trabajarlo de esa forma. El uso de herramientas para el manejo de estado va a depender de tu aplicación y la comunicación que existe dentro de ella, estas herramientas se recomiendan cuando tu aplicación es grande y necesitas compartir información entre páginas y componentes. Aplicarlas en proyectos pequeños lo que hace es agregar complejidad. Te comparto un enlace de redux donde te explican cuando puede usar react.
Para los que tenian este error como yo, les dejo la solución
todos.filter is not a function
TypeError: todos.filter is not a function
Les dejó dos imagenes con los pequeños cambios que le hice
Esto es el archivo useLocalStorage.js
Esto es en el archivo useTodos.js
Les dejo mi repo por si lo quieren ver en detalle
Hola Brenda gracias por tu solucion!! suerte en tu aventura de aprendizaje
Me arroja el siguiente error y no logro depurar el código. ¿A alguien le ha sucedido lo mismo?
Uncaught TypeError: Cannot read properties of undefined (reading 'filter').
tengo el mismo error!!
La manera que personalmente uso para evitar confusiones entre sincronizar y sincronizado es:
sync: sincronizar
synced: sincronizado
Me parece más conciso y simple de leer
Estuve un rato bastante largo intentando solucionar un problema sobre los estados en la función reducer y que mi componente no volvía a hacer render aunque el estado cambiaba.
Fue porque el hook useReducer interpreta que una propiedad en el estado cambió cuando es un objeto nuevo NO SOBRE MODIFICACIONES DE UN OBJETO. Esto aplica cuando nuestro estado tiene objetos internos en sus propiedades (como arrays u objects). Importante acordarse crear copias de estos objetos cuando sean propiedades del estado.
Para que quede más limpio y ordenado el código se puede dividir en carpetas el reducer y el initialState y luego llamarlo al archivo useLocalStorage.
Jajaja eres un crack pero basta con usar
onSync()SynchedSyncronize
synced / syncing
por que le gusta complicarseeee diosss miioooooooooo