No tienes acceso a esta clase

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

Aprende Ingl茅s, Programaci贸n, AI, Ciberseguridad y m谩s a precio especial.

Antes: $249

Currency
$209
Suscr铆bete

Termina en:

2 D铆as
19 Hrs
6 Min
57 Seg

useLocation: transferencia de datos por navegaci贸n

24/30
Recursos

Aportes 13

Preguntas 1

Ordenar por:

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

Yo he encontrado un error.
.
Resulta que la aplicaci贸n cada vez que damos click en los botones de a帽adir un TODO o editar un TODO, hace uso del custom hook useTodos() y este a su vez hace uso del custom hook useLocalStorage() (y como sabemos este es s铆ncrono, requiere de tiempo).
.
Entonces cada vez que accedemos a las rutas /new o /edit/ debemos esperar que carguen los todos del localStorage nuevamente porque los necesitamos para las funciones addTodo() y editTodo() y aqu铆 es donde est谩 el problema.
.
Si modificamos el setTimeout() de useLocalStorage() a 5 segundos por ejemplo y luego accedemos a /new o /edit y agregamos o editamos informaci贸n antes de que pasen 5 segundos habr谩 problemas.

  • En el caso de addTodo() se sobrescribir谩 la informaci贸n, porque la constante newTodos va a ser igual a un arreglo vac铆o.
  • En el caso de editTodo() se romper谩 la aplicaci贸n, porque la constante todoIndex va a ser -1.

.
Para solucionar esto lo que hice fue deshabilitar el <textarea> y el bot贸n de A帽adir/Editar usando el state loading de useTodos()

  • En newTodoPage() y EditTodoPage() agregue lo siguiente:
//use el loading y se lo pase al <TodoForm />
const { editTodo, getTodo, loading } = useTodos()

return (
	<TodoForm
		loading={loading}
		...
		...
)

  • En TodoForm() agregue lo siguiente:
function TodoForm(props) {
	...
	...

	return (
		...
		<textarea 
			disabled={props.loading}
			...
		/>
		<button
			disabled={props.loading}
		>
			{props.submitText}
		</button>
	)
}

Esta ser铆a mi respuesta al retor, cualquier sugerencia estar茅 pendiente:

React router v6

React router v5

Previamente, hab铆a publicado un c贸digo que ten铆a dos errores:

  • al entrar directamente a una url, state (location) no exist铆a y tiraba un error.
  • si el id del to-do no exist铆a, saltaba un error

Ya correg铆 esos errores, dejo el nuevo c贸digo abajo.

App.js

<Route path="/edit/:id" element={<EditTodoPage />} />

EditTodoPage.js

export function EditTodoPage() {
    const { editToDo, loading, getToDo } = useToDos()
    const { state } = useLocation()
    let { id } = useParams()
    id = Number(id) //useParams converts number to text. Just in case, it is converted to number again

    let toDoText

    if (!state) {
        if (loading) return <p>loading</p>
        let toDo = getToDo(id)
        if (!toDo) return <NotFound />
        toDoText = toDo.text
    } else ({ toDoText } = state)

    return (
        <TodoForm
            submitEvent={newText => editToDo({ id, newText })}
            title="Edit To-Do"
            submitText="Edit"
            defaultText={toDoText}
        />
    )
}

Para resolver el reto del minuto 13:22, le铆 la documentaci贸n del hook useNavigate() de React Router, y not茅 que la funci贸n navigate() no s贸lo recibe una ruta, sino tambi茅n un objeto de opciones:

Y entre las opciones recibe la propiedad state, entonces desde el HomePage, agregu茅 el objeto de opciones con la propiedad state a la funci贸n navigate(), asign谩ndole como valor al state el texto del TODO de cada TodoItem que est谩 siendo mapeado por el TodoList.

Luego en la p谩gina EditTodoPage, por medio del hook useLocation(), le asign茅 el valor del state a la propiedad defaultTodoText del componente TodoForm.

Y listo, de esta forma podemos enviar directamente el texto de cada TODO al formulario TodoForm sin necesidad de esperar los segundos para que carge el localStorage.

Toca ver varias veces esta clase馃馃お

Pens茅 que iba a poder con este reto, pero una vez m谩s encontr茅 varias formas de Como no hacerlo鈥D.
Aprend铆 que useLocation es inmutable.

鈥渟i, cambio un poquito el navegador鈥 jajajajaj

Alguien m谩s pens贸 que no tiene sentido pasar la informaci贸n por el location.state si de igual forma hay que esperar a que se carguen los TODOs del local storage antes de poder darle click al bot贸n de editar/a帽adir ?

Por ejemplo, si se demora 10 seg en cargar los TODOs y hacemos click en editar antes de que termine la carga, la aplicaci贸n se rompe, esto lo solucion茅 deshabilitando el bot贸n de editar hasta que terminara la carga鈥 pero esa soluci贸n no me convence ya que no hay ninguna ventaja en pasar los datos por el location.state

Mi soluci贸n

Mi soluci贸n fue pasar en el NavigateOptions.state el texto del TODO cuando se navega a la ruta 鈥/edit/:id鈥 :

        {todo => (
          <TodoItem
            key={todo.id}
            text={todo.text}
            completed={todo.completed}
            onComplete={() => completeTodo(todo.id)}
            onDelete={() => deleteTodo(todo.id)}
            onEdit={() => navigate('/edit/' + todo.id, {state: {text: todo.text} })}
          />
        )}

Luego en EditTodoPage se accede a ese objeto state mediante useLocation():

function EditTodoPage(){

   const { stateUpdaters } = useTodos();
   const { editTodo } = stateUpdaters;
   const params  = useParams();
   const id = Number(params.id);
   const location = useLocation();

    return(
        <TodoForm 
            label="Edita tu Todo"
            submitText='Actualizar'
            submitEvent={(newText) => editTodo(id, newText)}
            initialText={location.state?.text}
        />
    );
}

Juan dice que esta clase fue d铆ficil鈥
Para m铆 lo fue, pero por ese bendito loading que me hizo estar debuggeando un buen rato! 馃樀

Me estaba sucediendo un error, muestro screenshot:

.
Y suced铆a porque me sal铆a del NewPage hacia el HomePage sin que terminar谩n de cargar los todos, as铆 que, cuando ya hab铆an cargado y el estado loading cambia a true, el componente TodoForm ya est谩 desmontado, y ocasiona el error.
.
La soluci贸n a esto es DETENER la carga de los todos al salirnos del NewPage (y EditPage tambi茅n). C贸mo hacemos eso?
.
En efecto, como nos dice el error, debemos cancelar esa carga de todos desde una Cleanup Function en nuestro useEffect que genera el setTimeout dentro de useLocalStorage. Esto es lo equivalente a un willUnmount del antiguo React.

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

				if (!localStorageItem) {
					localStorage.setItem(itemName, JSON.stringify(initialValue));
					parsedItem = initialValue;
				} else {
					parsedItem = JSON.parse(localStorageItem);
				}

				onSuccess(parsedItem);
			} catch (error) {
				onError(error);
			}
		}, 3000);

		//CLEANUP FUNCTION
		return () => {
			clearInterval(timeout);
		};
	}, [sincronizedItem]);

Yo me propuse lograr la funcionalidad antes de ver el video de esta clase, les comparto mi soluci贸n:

  • Primero edit茅 la propiedad path de la etiqueta Route que nos lleva al componente EditTodoPage para que aceptara un par谩metro m谩s:
  • Luego le agreg茅 a la funci贸n navigate de onEdit el par谩metro todo.text
  • Y por 煤ltimo defin铆 ese texto como valor por defecto de newTodoValue en el componente TodoForm 馃槂

    Y listo 馃槂