No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripción 🔥

Aprende todo un fin de semana sin pagar una suscripción 🔥

Regístrate

Comienza en:

3D
21H
52M
35S

useLocation: transferencia de datos por navegación

24/30
Recursos

Aportes 10

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

Esta sería mi respuesta al retor, cualquier sugerencia estaré pendiente:

React router v6

React router v5

Toca ver varias veces esta clase🧐🤪

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.

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>
	)
}

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}
        />
    )
}

Pensé que iba a poder con este reto, pero una vez más encontré varias formas de Como no hacerlo…XD.
Aprendí que useLocation es inmutable.

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 😃

“si, cambio un poquito el navegador” jajajajaj