Sienndo creativos, asi quedo mi notFound
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
Convierte tus certificados en títulos universitarios en USA
Antes: $249
Paga en 4 cuotas sin intereses
Termina en:
Juan David Castro Gallego
Aportes 18
Preguntas 6
Sienndo creativos, asi quedo mi notFound
Como mi TODOs machine lo hice con la temática de Naruto, hice un simple not found component, solamente con una imagen y un título. así quedó.
Yo soy revelde y no le hice caso a la junta Directiva y estoy trabajando en react 18 jejejejje muy bueno el reto
Esta es la estructura que yo uso. Me parece bastante cómoda.
Para los que quieran usar Alias para hacer imports más limpios y evitar usar Paths extensos y relativos . Tienen que configurar su herramienta build tool.
.
En mi caso uso Vite.js entonces lo modifique de la siguiente manera
vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@App': '/src/App',
'@components': '/src/components',
'@hooks': '/src/hooks',
'@pages': '/src/pages',
// Add more aliases as needed
}
}
})
Tambien hice un archivo en el Root del projecto llamado jsconfig.json para ayudarle a VSCode a reconocer estos aliases y poder seguir usando auto-imports e IntelliSense.
jsconfig.json
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@App/*": ["src/App/*"],
"@components/*": ["src/components/*"],
"@hooks/*": ["src/hooks/*"],
"@pages/*": ["src/pages/*"],
// Add more aliases as needed
}
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
.
Una vez hecho esto ya podemos actualizar nuestros imports.
//import sin path Aliases
import SomeComponent from '../../components/SomeComponent';
//import con path aliases
import SomeComponent from '@components/SomeComponent';
Yo siempre uso alias. Me facilita mucho el trabajo.
Siempre me a gustado mucho esta estructura, carpetas para hooks, componentes y paginas.
mi organización:
Te dan puntos por esto, verdad?
bueno algo sencillo decidi crear un componente y su respectivo css
import React from "react";
import "./notfound.css"; // Importa los estilos CSS
const NotFound = () => {
return (
<div className="container">
<h1 className="heading">¡Oops, Te Perdiste!</h1>
<p>Esta página es tan escurridiza como un unicornio en patines.</p>
<img
className="image"
src="https://img.freepik.com/vector-gratis/lindo-unicornio-jugando-patinaje-sobre-ruedas-ilustracion_138676-3287.jpg?w=740&t=st=1691293684~exp=1691294284~hmac=b7bffe0c0e9c8be85358879314e1199cbaebdc0378cbaff6d8460804b88d8163"
alt="Lost Unicorn"
/>
</div>
);
};
export {NotFound} ;
css
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
font-family: sans-serif;
}
.heading {
font-size: 2rem;
margin-bottom: 1rem;
}
.image {
max-width: 50%;
height: auto;
}
En mi estructura tengo una carpeta llamada “Pages” y una llamada “Components”. Creo que tienen nombres bastantes descriptivos jajaja.
.
En mi caso, el componente App lo he introducido como cualquier otro componente dentro de la carpeta “Components” y tengo una carpeta de “Hooks” donde están los hooks ya creados y si se necesitan nuevos hooks también irán ahí
Como yo uso SASS tengo todos los estilos aparte
En mi caso suelo utilizar el NewPage también en el edit, solo que controlo si la ruta tiene algún id con el cual pueda buscar en la base de datos, en el caso de que exista el botón pasa de new a update y se cargan los datos en los campos.
Voy con React@18 y Material UI
.
Vamos a reestructurar el proyecto de TodoMachine
para remplazar portales y modales, por rutas utilizando React Router DOM
.
.
La estructura de carpetas será la siguiente.
.
public
src
- routes
- ui
- index.css
- index.js
.gitignore
README.md
package-lock.json
package.json
yarn.lock
.
Dentro de src
se va a dar el mayor cambio, puesto que ahora manejamos un archivo de routes que contiene nuestras rutas, nuestros custom hooks y la aplicación principal en App.js
.
.
routes
- edit
-- EditTodoPage.js
- home
-- HomePage.js
- new
-- NewTodoPage.js
- App.css
- App.js
- useLocalStorage.js
- useTodos.js
.
Cada ruta tiene su propia página o componente que se va a renderizar para esa ruta.
.
import React from 'react';
function EditTodoPage() {
return (
<p>Editar TODO</p>
);
}
export { EditTodoPage };
import React from 'react';
import { useTodos } from '../useTodos';
import { TodoHeader } from '../../ui/TodoHeader';
import { TodoCounter } from '../../ui/TodoCounter';
import { TodoSearch } from '../../ui/TodoSearch';
import { TodoList } from '../../ui/TodoList';
import { TodoItem } from '../../ui/TodoItem';
import { TodosError } from '../../ui/TodosError';
import { TodosLoading } from '../../ui/TodosLoading';
import { EmptyTodos } from '../../ui/EmptyTodos';
import { TodoForm } from '../../ui/TodoForm';
import { CreateTodoButton } from '../../ui/CreateTodoButton';
import { Modal } from '../../ui/Modal';
import { ChangeAlert } from '../../ui/ChangeAlert';
function HomePage() {
const { state, stateUpdaters } = useTodos();
const {
error,
loading,
searchedTodos,
totalTodos,
completedTodos,
openModal,
searchValue,
} = state;
const {
setOpenModal,
addTodo,
completeTodo,
deleteTodo,
setSearchValue,
sincronizeTodos,
} = stateUpdaters;
return (
<React.Fragment>
<TodoHeader loading={loading}>
<TodoCounter
totalTodos={totalTodos}
completedTodos={completedTodos}
/>
<TodoSearch
searchValue={searchValue}
setSearchValue={setSearchValue}
/>
</TodoHeader>
<TodoList
error={error}
loading={loading}
totalTodos={totalTodos}
searchedTodos={searchedTodos}
searchText={searchValue}
onError={() => <TodosError />}
onLoading={() => <TodosLoading />}
onEmptyTodos={() => <EmptyTodos />}
onEmptySearchResults={
(searchText) => <p>No hay resultados para {searchText}</p>
}
>
{todo => (
<TodoItem
key={todo.text}
text={todo.text}
completed={todo.completed}
onComplete={() => completeTodo(todo.text)}
onDelete={() => deleteTodo(todo.text)}
/>
)}
</TodoList>
{!!openModal && (
<Modal>
<TodoForm
addTodo={addTodo}
setOpenModal={setOpenModal}
/>
</Modal>
)}
<CreateTodoButton
setOpenModal={setOpenModal}
/>
<ChangeAlert
sincronize={sincronizeTodos}
/>
</React.Fragment>
);
}
export { HomePage };
import React from 'react';
function NewTodoPage() {
return (
<p>New Todo</p>
);
}
export { NewTodoPage };
.
Es evidente que las importaciones van a cambiar, debido a que todos nuestros componentes de interfaz se movieron a una carpeta llamada ui
, entre otros cambios.
.
La estructura de la carpeta ui
contempla lo siguiente.
.
ui
- ChangeAlert
- CreateTodoButton
- EmptyTodos
- Modal
- TodoCounter
- TodoForm
- TodoHeader
- TodoIcon
- TodoItem
- TodoList
- TodoSearch
- TodosError
- TodosLoading
.
A todo esto, los 2 archivos más importantes para poder migrar la aplicación a rutas serán index.js
dentro de src
, y App.js
que se encuentra dentro de routes
.
.
import React from 'react';
import ReactDOM from 'react-dom';
import { App } from './routes/App';
import './index.css';
ReactDOM.render(
<App />,
document.getElementById('root')
);
import React from 'react';
import { HashRouter, Route, Routes } from 'react-router-dom';
import { EditTodoPage } from './edit/EditTodoPage';
import { HomePage } from './home/HomePage';
import { NewTodoPage } from './new/NewTodoPage';
function App() {
return (
<HashRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/new" element={<NewTodoPage />} />
<Route path="/edit/:id" element={<EditTodoPage />} />
<Route path="*" element={<p>Not Found</p>} />
</Routes>
</HashRouter>
);
}
export { App };
.
En App.js
creamos la estructura principal de rutas utilizando a HashRouter
como provider con 4 rutas principales que ya hemos mencionado previamente, añadiendo una ruta adicional para rutas que sean Not Found
.
.
Finalmente lo exportamos como un export nombrado, por lo que lo importamos de la manera correspondiente desde el index.js
que se encuentra en src
.
Les dejo el código de mi App. Yo utilizo vite + typescript.
El tema del base y basename son configuraciones necesarias al subir a GitHub Pages y funcione correctamente pues no se trabaja en la ruta raiz.
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
base: '/todo_machine_ts/'
})
import { FC } from 'react'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { Home } from './pages/Home'
import { NewTodo } from './pages/NewTodo'
import { EditTodo } from './pages/EditTodo'
const App: FC = () => {
return (
<BrowserRouter basename='todo_machine_ts'>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/new' element={<NewTodo />} />
<Route path='/edit/:id' element={<EditTodo />} />
</Routes>
</BrowserRouter>
)
}
export default App
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?