No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Resolviendo los retos de StorageEventListener

16/19
Recursos

Aportes 32

Preguntas 4

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Con mi soluci贸n CSS, busqu茅 crear una Modal para atrapar la absoluta atenci贸n del usuario, con un fondo 鈥渃asi rojo鈥 para dar a entender que hay una alerta y un bot贸n que refleja la intenci贸n de la misma, adem谩s mientras la alerta est谩 abierta, el usuario no puede interactuar con el resto de la app. 馃槃

Codigo usado por el profesor:

function ChangeAlert({ show, toggleShow}) {
    if(show){
        return (
            <div className="ChangeAlert-bg">
                <div className="ChangeAlert-container">
                <p>Parece que cambiaste tus TODOs en otra pesta帽a o ventana del navegador.</p>
                <p>驴Quieres sincronizar tus TODOs?</p>
                <button
                    className="TodoForm-button TodoForm-button--add"
                    onClick={toggleShow}
                >
                    Yes!
                </button>
                </div>
            </div>
        );
    } else{
        return null;
    }
}

codigo del css:

.ChangeAlert-bg {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: #1e1e1f50;
    z-index: 2;
}

.ChangeAlert-container {
    position: fixed;
    bottom: -10px;
    left: -10px;
    right: -10px;
    padding: 34px;
    background-color: #1e1e1f;
    color: #f2f4f5;
    z-index: 2;
    text-align: center;
    font-size: 20px;
}

.ChangeAlert-container button {
    margin-top: 16px;
    margin-bottom: 16px;
}

Muestro c贸mo qued贸 mi modal para alertar a los ususarios. Lo que hice fue crear un estado de ModalType para que permitiera desplegar en el mismo modal usando las mismos estados para modal de antes 馃憞

Es poco pero es trabajo honesto

En lo personal no me gusta que de repente desaparezcan los TODOs, Yo los hice casi inutilizables agreg谩ndoles un Pseudo elemento con css y una opacidad del 25% para dar a entender que no se pueden usar hasta que se carguen los cambios.

Algo que si no me gusto es la notificaci贸n que ti agregaste, me parece que no va concorde al dise帽o de la aplicaci贸n, usar el negro de fondo para el div me parece que hace demasiado contraste, en lo personal prefiero usar el mismo color de fondo de la app.

Por un momento pens茅 que dir铆a 鈥淐ocinar los gatos鈥 jaja. Menos mal que fueron lentejas.

Yo no lo hice como un modal, me acord茅 de como lo hace twitter y me anim茅 a hacerlo as铆:

Yo hice un modal:

En App() le pase setOpenModal

<ChangeAlertWithStorageListener
        synchronize={synchronizeTodos}
        setOpenModal={setOpenModal}
/>

El Wrapper en la HOC as铆:

<WrapperComponent
            {...props}
            show={storageChange}
            toggleShow={toggleShow}
/>

Y el componente ChangeAlert recibi贸 setOpenModal en props:

const ChangeAlert = ({ show, toggleShow, setOpenModal }) => {
    const handleClick = () => {
        toggleShow()
        setOpenModal(false)
    }
    if (show) {
        return (
            <>
                <Modal>
                    <ChangeAlertForm onClick={handleClick} />
                </Modal>
            </>
        )
    }
    return null
}

No me gusta lo de preguntarle al usuario si quiere refrescar o no, me gusta mas lo responsivo que se siente la app cuando se actualiza autom谩ticamente por lo que me ide茅 una soluci贸n. Use el useStorageListener como custom Hook en useLocalStorage y asigne el valor de storageChange al useEffect en useLocalStorage como segundo paramentro, de esta forma, cada que haya un cambio en el estado storageChange se va a ejecutar, todo esto me ahorro el ChangeAlert y pasar estados a los dem谩s componentes,
y al inicio del useEffect en useLocalStorage se pone setLoading(true) y quedaria funcionando de est谩 manera

Les muestro como quedo mi mensaje de actualizaci贸n.
![](

Sigo sin poder ver nada en el navegador, he visto todo el curso as铆. 馃槬馃槬
.

Reutilic茅 el div modal para solo integrar un nuevo div con la alerta de refresh. En lo personal pas茅 el synchronizedItem hasta TodoList y utilic茅 ese estado para no mostrar con css la lista, pero creo que la soluci贸n de solo ocupar los estados loading y error son m谩s 贸ptimas.

Esta fue mi soluci贸n CSS ![](

lo que yo hice para poder eliminar a la hora de cargar fue hacer una funcion que llame deleteRenderItems a la cual le pase un array vacio ( [ ] ) a la funcion setItems quedando de la siguiente manera.

import React from "react";

function useLocalStorage(itemName, initialValue) {
  const [item, setItems] = React.useState(initialValue);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(false);
  const [sincronizedItem, setSincronizedItem] = React.useState(true);

  React.useEffect(() => {
    setTimeout(() => {
      try {
        const localStorageItem = localStorage.getItem(itemName);
        let parsedItem;

        if (!localStorageItem) {
          localStorage.setItem(itemName, JSON.stringify(initialValue));
          parsedItem = initialValue;
        } else {
          parsedItem = JSON.parse(localStorageItem);
        }
        setItems(parsedItem);
        setLoading(false);
        setSincronizedItem(true);
      } catch (error) {
        setError(error);
      }
    }, 500);
  }, [sincronizedItem]);

  const saveItem = (newItem) => {
    try {
      const stringifiedItem = JSON.stringify(newItem);
      localStorage.setItem(itemName, stringifiedItem);
      setItems(newItem);
    } catch (error) {
      setError(error);
    }
  };
  const sincronizeItem = () => {
    setLoading(true);
    setSincronizedItem(false);
  };
  const deleteRenderItems = () => {
    setItems([]);
  };
  return {
    deleteRenderItems,
    item,
    saveItem,
    loading,
    error,
    sincronizeItem,
  };
}

export { useLocalStorage };

y utilice lo pase por render props a nuestro HOC quedando asi .

import React from "react";

function withStorageListener(WrappedComponent) {
  return function WrappedComponentWithStorageListener(props) {
    const [storageChange, setStorageChange] = React.useState(false);
    window.addEventListener("storage", (change) => {
      if (change.key === "TODOS_V1") {
        console.log("Hubo cambios en TODOS_V1");
        setStorageChange(true);
      }
    });
    const toggleShow = () => {
      props.sincronize();
      setStorageChange(false);
      props.deleteRenderItems();
    };

    return <WrappedComponent show={storageChange} toggleShow={toggleShow} />;
  };
}

export { withStorageListener };

Para el reto de css use el mismo modal de la clase pero modifique el boton para que se viera como uno de recarga:

Para ellos use el caracter 鈥渃lockwise open circle arrow鈥 en su codigo hex:

HTML:

<button className="SyncTodosButton" onClick={toggleShow}>
	&#x21bb;
</button>

Y le a帽adi una peque帽a animacion para que diera el efecto de que debia ser pulsado, y un efecto de hover.

CSS:

.SyncTodosButton {
    background-color: #61DAFA;
    box-shadow: 0px 5px 25px rgba(97, 218, 250, 0.5);
    border: none;
    border-radius: 50%;
    cursor: pointer;
    font-size: 50px;
    font-weight: bold;
    color: #FAFAFA;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 64px;
    width: 64px;
    transform: rotate(0);
    transition: .5s ease;
    animation: 2s infinite changeAnimation;
}

.SyncTodosButton:hover {
    transform: rotate(360deg);
    animation: none;
}

@keyframes changeAnimation {
    25% {
        box-shadow: 0px 5px 25px 5px rgba(97, 218, 250, 0.5);
        background-color: #59c9e7;
    }
    37.5% {
        box-shadow: 0px 5px 25px 10px rgba(97, 218, 250, 0.5);
        background-color: #44b7d6;
    }
    50% {
        box-shadow: 0px 5px 25px 15px rgba(97, 218, 250, 0.5);
        background-color: #44b7d6;
    }
    62.5% {
        box-shadow: 0px 5px 25px 10px rgba(97, 218, 250, 0.5);
        background-color: #44b7d6;
    }
    75% {
        box-shadow: 0px 5px 25px 5px rgba(97, 218, 250, 0.5);
        background-color: #59c9e7;

    }
    100% {
        box-shadow: 0px 5px 25px rgba(97, 218, 250, 0.5);
        background-color: #61DAFA;

    }
}

yo hice una pantalla bien intrusiva como con el modal.
Mientras la gente no entre desde inspeccionar y lo borre, no hay problema
![](

Antes de esta clase intent茅 quitar los To Do鈥檚 para que no se vieran durante la carga pero lo hice diferente.
En el useLocalStorage.js > funci贸n para sincronizar que le puse 鈥渟ync鈥 en vez de 鈥渟yncronize鈥 como le puso el profe

const sync = () => {
	setItem([]);
	setLoading(true);
	setSincronize(false);
}

O sea, aparte del setLoading y setSincronize, reutilic茅 el setItem que devolv铆a el array parseado y le puse que durante la carga est茅 vac铆o.
.
Hay alguna desventaja respecto a la propuesta del profe?

Hasta ahora llevo el proyecto as铆: https://jocad7.github.io/to-do-project/

No me enfoque tanto en el css.

Creo que todos tuvimos la misma idea jajaja Cool!

Qu茅 tal si hacemos que los Todos se actualicen autom谩ticamente, sin necesidad de ning煤n bot贸n? Me parece m谩s User Friendly, a todos nos gusta la automatizaci贸n.

Muy buenos estos patrones de dise帽o de React!

Agregue el Z-Index para no acceder al boton de add Todos

Solo realize esto y ya se quitan los otros TODOs

un peque帽o aporte: En react 18 ya no es necesario el boton de actualizar lo hace automatico

Mi soluci贸n para ocultar la lista fue agregar en el hock de useStorageTodo dentro de la funci贸n sincroniced agregu茅 setTodo([ ])
   {!props.loading && !props.error && props.searchedTodos.map(renderThis)}      

Codigo TypeScript de la clase:

import { FC } from 'react'
import { withStorageListener } from "./withStorageListener"
import './ChangeAlert.css'

interface Props {
    show: boolean,
    toggleShow: ()=>void,
    sincronizeTodos:()=>void
}

const ChangeAlert:FC<Props> = ({
    show,
    toggleShow,
    sincronizeTodos
})=> {

    if(show){
        return(
            <div className='ChangeAlert-bg'>
                <div className='ChangeAlert-container'>
                    <p>Parece que cambiaste tus TODOs en otra pesta帽a o ventana del navegador.</p>
                    <p>驴Quieres sincronizar tus TODOs?</p>
                    <button
                        className="TodoForm-button TodoForm-button--add"
                        onClick={()=>{
                            toggleShow();
                            sincronizeTodos();
                        }}
                    >
                        Yes!
                    </button>

                </div>
            </div>
        )
    } else {
        return null
    }
}

const ChangeAlertWithStorageListener = withStorageListener(ChangeAlert);

export { ChangeAlertWithStorageListener }
.ChangeAlert-bg {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: #1e1e1f50;
    z-index: 2;
}

.ChangeAlert-container {
    position: fixed;
    bottom: -10px;
    left: -10px;
    right: -10px;
    padding: 34px;
    background-color: #1e1e1f;
    color: #f2f4f5;
    z-index: 2;
    text-align: center;
    font-size: 20px;
}

.ChangeAlert-container button {
    margin-top: 16px;
    margin-bottom: 16px;
}

import { FC, useEffect, useState } from "react"

function withStorageListener<T>(
    WrappedComponent: FC<T>
) {
    return function WrappedComponentWithStorageListener(props:Omit<T, "show" | "toggleShow">){
        
        const [storageChange, setStorageChange] = useState(false);

        useEffect(()=>{

            const functionHandler = (change: StorageEvent)=>{
                if(change.key=== "TODOS_V1"){
                    console.log('Hubo cambios en TODOS_V1');
                    setStorageChange(true)
                }

            }

            window.addEventListener('storage', functionHandler)

            return ()=>{
                window.removeEventListener('storage', functionHandler)
            }

        }, [])

        const toggleShow = ()=>{
            setStorageChange(false)
        }

        return (
            <WrappedComponent 
                {...(props as T)}
                show={storageChange}
                toggleShow={toggleShow}          
            />
        )
    }   
}

export { withStorageListener }

En mi caso decid铆 que al haber un cambio de una vez actualice los ToDos:

useEffect(() => {
		initialize();

		const onChange = (change: StorageEvent) => {
			console.log({ change });
			if (change.key === "todos") {
				const newTodos = JSON.parse(change.newValue || "[]");
				dispatch({ type: "UPDATE_TODOS", payload: newTodos });
			}
		};

		window.addEventListener("storage", onChange);

		return () => {
			window.removeEventListener("storage", onChange);
		};
	}, []);

Ta potente React.
Page
Code

As铆 quedo mi advertencia con un 鈥渕odal鈥 en toda la pantalla visible del navegador 馃槃