Esta sería mi respuesta al retor, cualquier sugerencia estaré pendiente:
React router v6
React router v5
Fundamentos de navegación en la web
¿Cuándo necesitas React Router?
SSR vs. Single Page Applications
Versiones de React Router: ¿Por qué son tantas? ¿Cuál elegir?
Introducción a React Router DOM 6
Instalación de React Router DOM 6
BrowserRouter vs. HashRouter
Route: componentes de navegación
Link vs. NavLink
useParams: rutas dinámicas
useNavigate: historial de navegación
Outlet: nested routes
Fake authentication con React Router DOM 6
useAuth: login y logout
Menú con rutas públicas y privadas
Navigate y redirects: protegiendo rutas privadas
Roles y permisos
Reto: composición de componentes con navegación
Reto: UX de login y logout
Reto: roles complejos
React Router en TODO Machine
Integrando React Router a proyectos en React
Creando las rutas de TODO Machine
Botón de editar TODOs
Generador automático de IDs
Cambiando modales por navegación
Obtener y editar TODOs
useLocation: transferencia de datos por navegación
Deploy con React Router en GitHub Pages
Próximos pasos
Reto: página de búsquedas con navegación
Reto: TODO Machine con React Router DOM 5
Reto: PlatziMovies con React Router
Reto: crea tu propio React Router
Espera más cursos de React.js
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Aportes 10
Preguntas 1
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.
addTodo()
se sobrescribirá la información, porque la constante newTodos
va a ser igual a un arreglo vacío.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()
newTodoPage()
y EditTodoPage()
agregue lo siguiente://use el loading y se lo pase al <TodoForm />
const { editTodo, getTodo, loading } = useTodos()
return (
<TodoForm
loading={loading}
...
...
)
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:
state
(location) no existía y tiraba un error.Ya corregí esos errores, dejo el nuevo código abajo.
<Route path="/edit/:id" element={<EditTodoPage />} />
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:
“si, cambio un poquito el navegador” jajajajaj
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?
o inicia sesión.