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
You don't have access to this class
Keep learning! Join and start boosting your career
Welcome to the world of React Routing. A key component in building modern applications with React is how to organize our files and structure our folders to effectively handle multiple views or routes. In this analysis, we'll break down how to structure a project with React Router DOM and share helpful tips for you to apply this methodology in your own work.
React Router DOM is an essential library for handling navigation in React applications. It allows you to define multiple routes in a single application, improving its fluidity and modularity.
A good strategy starts by organizing and dividing your project into key folders. Let's break down an example of how you might organize your React project:
UI folder:
Routes folder:
ComponentA.jsx
ComponentB.jsx
[...]
HomePage.jsx
NewAllPage.jsx
EditAllPage.jsx
Implementing React Router requires configuring a number of routes in your App component. We will use HashRouter
to handle the routes in our project.
import React from 'react';import { HashRouter as Router, Route, Switch } from 'react-router-dom';import HomePage from './Routes/Home/HomePage';import EditTodoPage from './Routes/Edit/EditTodoPage';import NewTodoPage from './Routes/New/NewTodoPage';
function App() { return ( <Router> <Switch> {/* Route Home*/} <Route exact path="/" component={HomePage}/> {/* Route NewTask*/} <Route path="/new" component={NewTodoPage}/> {/* Route Edit Task with Dynamic Parameter*/} <Route path="/edit/:id" component={EditTodoPage}/> {/* Handling not found routes*/} <Route path="*" render={() => <p>Not found</p>}/> </Switch> </Router> );}
export default App;
Automatic imports: When moving files, some development environments such as Visual Studio Code can automatically adjust import paths.
Use of aliases: Consider using aliases for imports, which will make it easier to manage complex and repetitive references in your files.
Dynamic path handling: Use patterns in paths to support paths that require parameters, such as IDs, allowing specific components for actions such as editing a To Do.
With this base structure and configuration, it is crucial to maintain an iterative approach. As your application grows, take advantage of React Router DOM capabilities to:
Stay motivated and keep innovating in the organization of your applications, this not only improves the user experience, but also yours as a developer. What is the structure that has worked best for you? Share your experiences in the comments!
Contributions 20
Questions 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:
.
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
.
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
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
Want to see more contributions, questions and answers from the community?