No tienes acceso a esta clase

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

Completando el StorageEventListener

15/19
Recursos

Aportes 21

Preguntas 7

Ordenar por:

Los aportes, preguntas y respuestas son vitales para aprender en comunidad. Reg铆strate o inicia sesi贸n para participar.

Les doy la bienvenida a una nueva edici贸n de鈥
馃寛 Encuentra el error del profesor 馃寛
Estrellita a la primera persona que lo resuelva. 馃槈

.

馃憠 驴Cu谩l es el error con el c贸digo de esta clase?

  • Pista #1: est谩 relacionado a rendimiento
  • Pista #2: est谩 relacionado a los efectos

.

Pero 驴Juan, cu谩les efectos?
Exacto, 驴cu谩les efectos? Ese es el problema鈥

.

Respuestas aqu铆 en los comentarios 馃憞

Aporte respecto al event listener "storage" (addEventListener(鈥榮torage鈥)):

No funcionar谩 en la misma p谩gina que realiza los cambios; en realidad, es una forma de que otras p谩ginas del dominio usen el almacenamiento para sincronizar los cambios que se realicen. Las p谩ginas de otros dominios no pueden acceder a los mismos objetos de almacenamiento.

Esto lo saqu茅 de MDN
![](

Para que no aparezca los todos mientras est谩n sincroniz谩ndose

{!props.loading && props.searchedTodos.map(renderFunc)}

Estuve lidiando mucho rato con un concepto que entend铆 mal. Ya que no me aparec铆a el mensaje de cambio, pero era porque solo estaba usando una ventana. El evento se dispara cuando se modifica el local storage en el contexto de otro documento. Les dejo enlace por si les pasa igual. En resumen, tienen que tener dos pesta帽as abiertas
M谩s informaci贸n

Se crea css para mostrar el boton de refresh y se pasa a una ventana modal

Con respecto a como se soluciono el hecho que no se mostrara el listado y solo el skeleton loading queda asi mi solucion

import "./todoList.css";
const TodoList = ({
  children,
  error,
  loading,
  showEmptyTodos,
  showRender,
  showEmptySearchResults,
  onError,
  onLoading,
  onEmptyTodos,
  onEmptySearchResults,
  render
}) => {
  return (
    <section className="todolist-container">
      {error && onError()}
      {loading && onLoading()}
      {showEmptyTodos && onEmptyTodos()}
      {showEmptySearchResults && onEmptySearchResults()}
      {showRender && render()}
      <ul>{children}</ul>
    </section>
  );
};

export default TodoList;

Repo

Project TODOs

import React from 'react';
import { withStorageListener } from './withStorageListener';
// Se importa el HOC



//Componente
function Changealert({show,toggleShow,setItem}){

    if(show){  //Si show es verdadero
        return (

            <div>
                 <p>Hubo Cambios</p>
                 <button onClick={()=>{
                     
                     toggleShow(false);

                     const localStorageItem = localStorage.getItem('TODOS_V1');
                     const parsedItem = JSON.parse(localStorageItem);         
                     setItem(parsedItem)
                     
                     }}>Volver a cargar la informaci贸n</button>
                
            </div>

        );

    }else{
            
        return null;

    }

       

}

const ChangeAlertWithStorageListener=withStorageListener(Changealert);
//Se crea una variable , y envuelve en el HOC componente Changealert


export {ChangeAlertWithStorageListener};
//Se exporta este vendria siendo el componente de verdad

Para recargar la p谩gina en onClick llame 煤nicamente window.location.reload() y al recargar la ya no hac铆a falta toggleShow porque por defecto se volv铆a a false.

<button  onClick={() => {window.location.reload();}}>

No se que tan malooo sea hacer esto, pero toda la parte de la sincronizaci贸n la veo m谩s sencilla de hacerla asi simplemente:

function useLocalStorage(itemName, defaultValue = [], withSync = true) {

    const [sync, setSync] = React.useState(false)
    const [loading, setLoading] = React.useState(true);
    const [items, setItems] = React.useState(defaultValue);
    const [error, setError] = React.useState(false);

    if (withSync) {
        window.addEventListener("storage", () => {
            setSync(sync + 1);
        });
    }

Si esto genera problemas de optimizaci贸n o se considera una mala practica, pues creo que ahi esta el detalle, pero si no para mi queda de lujo 馃槀

As铆 es como resolv铆 los retos agregue una validaci贸n para no iterar los elementos al menos que no hubiera un error y no se encontrar谩 cargando la App. Puse un bot贸n para darle al usuario la posibilidad de no recargar la p谩gina.

antes de ver la solucion de eprofe lo que hice fue que el pedido de el contenido de local storage fuese una funcion tal que asi y cada que haya u cambio en storage invocar a update() y el cartel lo oculto en 3s para que no sea molesto y tambien se cierra con el botton

const update= ()=>{
        try{...
        }catch(err){...
        }
    }
React.useEffect(()=>{
    setTimeout(()=>{
        update();
        },1500);
    }, []);

Para mostrar los cambios al hacer click en el boton, lo que hice fue -> <button
onClick={() => window.location.reload(false)}
>
Volver a cargar la informacion
</button>
</div>

Mi soluci贸n a que no salgan los todos mientras est谩 en loading fue a帽adir una condici贸n extra antes de renderizar los todos, esa condici贸n es !props.loading, para que si el valor de loading es true no se renderice nada y cuando sea false ya pueda renderizar 馃槃

Buenas, al desaf铆o del profe Juan Dav铆d lo resolv铆 de dos formas, una f谩cil y r谩pida pero que es muy muy b谩sica y otra m谩s pensada.
La primera simplemente agregue un window.location.reload() en la funci贸n del bot贸n.
La segunda llev茅 el estado storageChange al hook useLocationStorage para que el useEffect corra cada vez que ese estado se actualice.
Sigo con el video!

Yo lo que hice para el reto de al final fue pasarle al TodoItem la propiedad loading

<TodoItem
                key={todo.text}
                text={todo.text}
                loading={loading}
                completed={todo.completed}
                onComplete={() => completeTodo(todo.text)}
                onDelete={() => deleteTodo(todo.text)}
/>

despu茅s en TodoItem checo si loading es true y si es true le agrego la clase TodoItem鈥搇oading

<li className={`TodoItem ${!!props.loading && 'TodoItem--loading'}` }>
      <CompleteIcon 
        completed={props.completed}
        onComplete={props.onComplete}
      />
      <p 
      className={`TodoItem-p ${props.completed && 'TodoItem-p--complete'}`}>
        {props.text}
      </p>
      <DeleteIcon
      onDelete={props.onDelete}
      />
    </li>

lo que hace esa clase es hacerle un display none a los items

 .TodoItem--loading{
    display: none;
  }

y tada!! ya no aparecen los todosmientras se sincronizan los todos

Para que no aparezcan mientras se actualiza, prefer铆 afectar de una vez la funci贸n Render, en mi Render Props:

	render={todo => (
            (sincronizedTodos) ?
              <TodoItem 
                key={todo.text} 
                text={todo.text} 
                completed={todo.completed} 
                color={todo.color} 
                todoComplete={() => todoComplete(todo.text)} 
                todoDelete={() => todoDelete(todo.text)}
              />
              : null
          )

Soluci贸n a los retos:
Para que al cargar no mostrar los TODOs:

import './TodoList.css'

function TodoList(props) {
    return (
        <section className="TodoList-container">
            {props.error && props.onError()}
            {props.loading && props.onLoading()}
            {(!props.loading && !props.totalTodos) && props.onEmpty()}
            {(Boolean(props.totalTodos) && !props.searchedTodos.length) && props.onEmptySearchResults(props.searchText)}

            <ul>
                {!props.loading && props.searchedTodos.map(props.render || props.children)}
            </ul>
        </section>
    )
}

export { TodoList }

En cuanto a no dejar modificar hasta que se actualice:

Agregaria en useLocalStorage:

const [canChange, setCanChange ] = React.useState(true);

Y luego lo acomodo a los diferentes componentes:

function CreateTodoButton({setOpenModal,canChange}) {
    const onClickButton = () =>{
        setOpenModal(prevState=>!prevState);
    }

    return (
        <button 
        className="CreateTodoButton"
        onClick={onClickButton}
        disabled={!canChange}
        >+</button>
    )
}

export { CreateTodoButton }

Si les queda dudas me lo piden y agrego los detalles en los comentarios de este comentario jejeje

yo simplemente lo que hice fue algo sensillo coloque dentro del button una etiqueta a con href="." y esto automaticamente me recarga la pagina

function ChangeAlert({show, toggleShow}) {
  if (show) {
    return (
      <div>
        <p>Hubo Cambios</p>
        <button
          onClick={() => toggleShow(false)}
        >
        <a href=".">Volver a cargar</a>
        </button>
      </div>
    );
  } else {
    return null;
  }
}

Lo que yo hice para solucionar el reto fue exportar la variable 鈥渟incronizedItem鈥 del hook useLocalStorage, la importe en el hook useTodos y la volvi a exportar en este, luego la importe en el componente App y se la env铆e como props a mi componente TodoList, en el componente TodoList solo valide lo siguiente.

  {
        props.sincronizing && props.searchedTodos.map( todo => renderFunc(todo))
      }

El reto es bastante sencillo鈥 bueno para m铆 qu茅 tengo experiencia animando cosas con css y js. El 煤nico problema est谩 en que firefox no permite hacer un drop image en este contendor 馃槮 no lo podr谩n ver.

Lo 煤nico que hice es agregar condiciones que involucren clases para ciertos elementos que ser谩n afectados con los estados de la p谩gina

Como pueden ver aqu铆, solo agregu茅 como dependencia del elemento 茅l prop.loading

Aqu铆 se ve el uso que le doy, si la p谩gina est谩 cargando, agrego una opacidad en los items y posicione un pseudo-elemento para evitar el uso de los items

<li className={`TodoItem ${props.loading? 'TodoItem-Loading' : ''}`}>

Sin necesidad de modificar el c贸digo que tenemos y sin cambios bruscos al momento de carga la nueva informaci贸n

Quiz谩s cuando termine el curso deje el repositorio para que lo vean

Mmm me gust贸 esta clase, pero creo que se sobrecomplic贸 algo que en realidad es muy simple.
.
Entiendo que es con fines educativos, pero resulta un poco mareante.
.
En lugar de usar HOCs, tranquilamente podr铆amos mostrar el alert con:

{ sincronized && <AlertWithStorageListener /> }

Esto funciona, pero me queda la duda, es esto correcto y la complejizaci贸n con HOCs que se hace en la clase es meramente con fines educativos, o tiene raz贸n de ser el hecho de haber hecho este HOC?

He tenido problemas con el sincronizeTodos por inercia de mi parte he colocado sincronizedTodos en mi caso me hubiera gustado que la palabra fuera otra mas diferencial alguna sugerencia ?