Este articulo es una joya y les ayudará a notar las diferencias
https://alligator.io/react/reach-router-vs-react-router/
Introducción al curso avanzado de React
Qué necesitas para este curso y qué aprenderás sobre React.js
Proyecto y tecnologías que usaremos
Preparando el entorno de desarrollo
Clonando el repositorio e instalando Webpack
Instalación de React y Babel
Zeit es ahora Vercel
Linter, extensiones y deploy con Now
Creando la interfaz con styled-components
¿Qué es CSS-in-JS?
Creando nuestro primer componente: Category
Creando ListOfCategories y estilos globales
Usar información real de las categorías
Creando PhotoCard y usando react-icon
SVGR: de SVG a componente de ReactJS
Creando animaciones con keyframes
Hooks
¿Qué son los Hooks?
useEffect: limpiando eventos
useCategoriesData
Usando Intersection Observer
Uso de polyfill de Intersection Observer e imports dinámicos
Usando el localStorage para guardar los likes
Custom Hooks: useNearScreen y useLocalStorage
GraphQL y React Apollo
¿Qué es GraphQL y React Apollo? Inicializando React Apollo Client y primer HoC
Parámetros para un query con GraphQL
Usar render Props para recuperar una foto
Refactorizando y usando variables de loading y error
Usando las mutaciones con los likes
Reach Router
¿Qué es Reach Router? Creando la ruta Home
Usando Link para evitar recargar la página
Creando la página Detail
Agregando un NavBar a nuestra app
Estilando las páginas activas
Rutas protegidas
Gestión del usuario
Introducción a React.Context
Creación del componente UserForm; y Hook useInputValue
Estilando el formulario
Mutaciones para registro
Controlar estado de carga y error al registrar un usuario
Mutaciones para iniciar sesión
Persistiendo datos en Session Storage
Hacer like como usuario registrado
Mostrar favoritos y solucionar fetch policy
Cerrar sesión
Mejores prácticas, SEO y recomendaciones
Últimos retoques a las rutas de nuestra aplicación
React Helmet
Midiendo el performance de nuestra app y usando React.memo()
React.lazy() y componente Suspense
Usando PropTypes para validar las props
PWA: generando el manifest
PWA: soporte offline
Testing con Cypress
Conclusiones
¡Felicidades!
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Reach Router es una potente librería de enrutamiento para React, que te permite construir un único componente que puede renderizar diferentes elementos de UI para diferentes rutas. Reach Router es una versión simplificada y mejor optimizada de React Router.
Su creador es Ryan Florence, el mismo creador de React Router. Se anunció que a partir de la versión V6 de React Router, Reach Router y React Router volverán a unirse en un mismo proyecto.
Reach Router es una poderosa biblioteca de enrutamiento que proporciona un único componente para renderizar diferentes elementos de la interfaz de usuario para diferentes rutas. Esto simplifica el proceso de enrutamiento de manera significativa.
Con él no tienes que usar objetos de ruta individuales o escribir declaraciones if-else anidadas en tu código. Todo lo que tienes que hacer es crear un módulo y añadir la importación del enrutador para utilizarlo con tu aplicación.
Reach-router es un paquete de enrutamiento que se puede adjuntar a la aplicación React. Ayuda a los desarrolladores a crear UIs escalables con varios componentes sin preocuparse del enrutamiento.
Según la documentación oficial, “React-router es una biblioteca de enrutamiento completa para React”. Pero en caso de que no estés usando React en tu proyecto, reach-router proporciona una excelente opción para el enrutamiento en tu aplicación. Reach-router ha sido fuertemente probado por el equipo de desarrollo de Facebook.
Usar Reach Router en tu aplicación es bastante sencillo. Solo tienes que instalarlo a través de npm, crear rutas y configurarlas a través de archivos de configuración o con el middleware redux al construir la aplicación.
Instalamos react-router-dom
npm i react-router-dom
Luego escribimos el siguiente codigo: ListOfCategories
const renderList = (fixed)=>(
<List fixed={fixed}>
{
loading?
[1,2,3,,4,5,6].map(category=><Item key={category}><CategorySkeleton /></Item>):
categories.map(category=><Item key={category.id}><Category {...category} path={`/pet/${category.id}`} /></Item>)
}
</List>
)
return (
<>
{renderList()}
{showFixed && renderList(true)}
</>
)
App.js
import Reactfrom 'react'
import { Route, BrowserRouter, Routes }from 'react-router-dom'
import { GlobalStyle }from './styles/GlobalStyles'
// import { ListOfPhotoCards } from './components/ListOfPhotoCards'
import { Logo }from './components/Logo'
import { PhotoCardWithQuery }from './container/PhotoCardWithQuery'
import { Home }from './pages/Home'
exportconst App = () => {
const urlParams =new URLSearchParams(location.search);
const detailId = urlParams.get('detail');
return (
<>
<GlobalStyle />
<Logo />
{
detailId?
<PhotoCardWithQuery id={detailId} />:(
<BrowserRouter>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/pet/:id' element={<Home />} />
</Routes>
</BrowserRouter>
)
}
</>
)
}
Home.js
import Reactfrom 'react'
import { useParams }from 'react-router-dom'
import { ListOfCategories }from '../components/ListOfCategories'
import { ListOfPhotoCardsContainer }from '../container/ListOfPhotoCardsContainer'
exportconst Home = ()=>{
const params = useParams();
console.log(params)
return (
<>
<ListOfCategories />
<ListOfPhotoCardsContainer categoryId={params.id} />
</>
)
}
Contribución creada con los aportes de: Max Andy Diaz Neyra.
Aportes 52
Preguntas 5
Este articulo es una joya y les ayudará a notar las diferencias
https://alligator.io/react/reach-router-vs-react-router/
De manera personal prefiero poner el fallback en el archivo de webpack, lo comparto por si a alguien le sirve
devServer: {
historyApiFallback: {
disableDotRule: true
}
Para pasar parametros con 'react-route-dom’
App.js
import React from 'react'
import { Route, BrowserRouter, Routes } from 'react-router-dom'
import { GlobalStyle } from './styles/GlobalStyles'
import { Logo } from './Components/Logo'
import { PhotoCardWithQuery } from './Container/PhotoCardWithQuery'
import { Home } from './Components/Pages/Home'
export const App = () => {
const urlParams = new window.URLSearchParams(window.location.search)
const detailId = urlParams.get('detail')
return (
<div>
<GlobalStyle />
<Logo />
{
detailId
? (<PhotoCardWithQuery id={detailId} />)
: (
<BrowserRouter>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/pet/:id' element={<Home />} />
</Routes>
</BrowserRouter>)
}
</div>
)
}
Home.js
import React from 'react'
import { useParams } from 'react-router'
import { ListOfCategories } from '../ListOfCategories'
import { ListOfPhotoCards } from '../ListOfPhotoCards'
export const Home = () => {
// const { id } = props.match.params
const params = useParams()
return (
<>
<ListOfCategories />
<ListOfPhotoCards categoryId={params.id} />
</>
)
}
Si no les deja instalar npm install @reach/router agreguen esto al final y lo instalará y así todos los pasos del profe son correctos:
npm install @reach/router --legacy-peer-deps
A la fecha del 3 de julio del 2022, utilizando react router dom , instalamos la dependencia con el comando
npm i react-router-dom
Y el código quedaría de la siguiente forma:
App.js
import React from 'react'
import { PhotoCardWithQuery } from './containers/PhotoCardWithQuery'
import { Home } from './pages/Home'
import { GlobalStyle } from './styles/GlobalStyles'
import { Logo } from './components/Logo'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
export const App = () => {
const urlParams = new window.URLSearchParams(window.location.search)
const detailId = urlParams.get('detail');
return (
<div>
<GlobalStyle />
<Logo />
{
detailId
? <PhotoCardWithQuery id={detailId} />
: <BrowserRouter>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/pet/:id' element={<Home />} />
</Routes>
</BrowserRouter>
}
</div>
)
}
Home.js
import React, { Fragment } from 'react';
import { ListOfPhotoCardsContainer } from '../containers/ListOfPhotoCards'
import { ListOfCategories } from '../components/ListOfCategories'
import { useParams } from "react-router-dom";
export const Home = () => {
let params = useParams();
return (
<Fragment>
<ListOfCategories />
<ListOfPhotoCardsContainer categoryId={params.id} />
</Fragment>
)
}
Actualmente en 2021 han cambiado muchas cosas
import { BrowserRouter, Route } from 'react-router-dom'
<BrowserRouter>
<Route exact path='/' render={(props) => <Home {...props} />} />
<Route exact path='/pet/:id' render={(props) => <Home {...props} />} />
</BrowserRouter>
O pueden poner directamente el componente
Ahora tuve un problema el path era un sting que no me traía un id por eso en el home hay que hacer esto
import React from 'react'
import { ListOfPhotoCards } from '../components/ListOfPhotoCards'
import { ListOfCategories } from '../components/ListOfCategories'
import { withRouter } from 'react-router-dom'
function Home (props) {
const { id } = props.match.params
console.log(parseFloat(id))
return (
<>
<ListOfCategories />
<ListOfPhotoCards categoryId={parseFloat(id)} />
</>
)
}
export default withRouter(Home)
lo envolvemos con withRouter, el i viene como strign hay que pasarlo a numero !!!
Webpack config para que funcionen las rutas (agrege publicPath y historyApiFallback)
mas info: https://webpack.js.org/configuration/dev-server/
module.exports = {
entry: ['@babel/polyfill', './src/index.js'],
output: {
filename: 'app.bundle.js',
publicPath: '/'
},
devServer: {
historyApiFallback: {
disableDotRule: true
},
liveReload: true
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
})
],
module: {
rules: [
{
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
loader: 'graphql-tag/loader'
},
{
test: /\.(js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
}
}
Hola compañeros del futuro. Este comentario es del 6 de noviembre de 2021. Después de mi derrota con el código el día de ayer, regreso de nuevo con otra solución
despues de buscar un poco y hacer todo un poco mas sencillo, hice uso del hook useParams de react-roruter-dom, este permite obtener información de la URL en la que nos encontramos para poderla usar como parámetro en las funciones que hacen render de los componentes.
Les dejo el código:
App,jsx
import React from 'react'
import { Logo } from './components/Logo'
import { PhotoCardWithQuery } from './container/PhotoCardWithQuery'
import { Home } from './pages/Home'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { GlobalStyle } from './components/styles/GlobalStyles'
const App = () => {
return (
<BrowserRouter>
<GlobalStyle />
<Logo />
<Routes>
<Route exact path='/' element={<Home />} />
<Route path='/pet/:id' element={<Home />} />
<Route path='/detail/:id' element={<PhotoCardWithQuery />} />
</Routes>
</BrowserRouter>
)
}
export { App }
Home.jsx
import React from 'react'
import { ListOfCategories } from '../components/ListOfCategories'
import { ListOfPhotoCardsComponent } from '../components/ListOfPhotoCardsComponent'
const Home = () => {
return (
<>
<ListOfCategories />
<ListOfPhotoCardsComponent />
</>
)
}
export { Home }
ListofPhtoCardsComponent.jsx
import React from 'react'
import { PhotoCard } from './PhotoCard'
import { ListOfPhotoCards } from '../container/ListOfPhotoCards'
import { useParams } from 'react-router'
const ListOfPhotoCardsComponent = () => {
const { id } = useParams()
const categoryId = id
const { loading, error, data } = ListOfPhotoCards({ categoryId })
if (error) {
return <h2>Internal Server Error</h2>
}
if (loading) {
return <h2>Loading...</h2>
}
return (
<ul>
{data.photos.map((photo) => (
<PhotoCard key={photo.id} {...photo} />
))}
</ul>
)
}
export { ListOfPhotoCardsComponent }
Este es uno de los componentes.
El repositorio lo tengo aquí 😄
https://github.com/onedrako/petstagram
Para esta clase el commit es el “Fix the routes using useParams” o el d72abdca8c67d308120318030dc382396b0d9d6b
Les comparto los ajustes que hice para que funcionara con React Router
En el Home.js
export const Home = (props) => {
const {
match: {
params: { id }
}
} = props
return (
<>
<ListOfCategories />
<ListOfPhotoCards categoryId={id} />
</>
)
}
y en el App.js
import React from 'react'
import { Route, BrowserRouter, Switch } from 'react-router-dom'
import { Logo } from './components/Logo'
import { GlobalStyles } from './styles/GlobalStyles'
import { PhotoCardWithQuery } from './container/PhotoCardWithQuery'
import { Home } from './pages/Home'
export const App = () => {
const urlParams = new window.URLSearchParams(window.location.search)
const detailId = urlParams.get('detail')
return (
<>
<GlobalStyles />
<Logo />
{detailId
? (
<>
<PhotoCardWithQuery id={detailId} />
</>
)
: (
<BrowserRouter>
<Switch>
<Route path='/pet/:id' component={Home} />
<Route path='/' component={Home} />
</Switch>
</BrowserRouter>
)}
</>
)
}
Para hacerlo en webpack se necesita agregar dos cosas, el publicPath en output e historyApiFallback en devServer:
output: { publicPath: '/', }, devServer: { historyApiFallback: true },
para los que estan haciendo el curso recientemente, ahora en el home(id) no llega el id si no toda la información del path, así que hay que poner
export const Home = (path) => {
console.log('path > ', path)
return (
<Fragment>
<ListOfCategories />
<ListOfPhotoCards categoryId={path.id} />
</Fragment>
)
}```
Para Noviembre de 2022 ha cambiado un monton la libreria. Para empezar ahora se instala React Router ya que como dijo el profe que pasaría, ahora se han fusionado en un solo proyecto y así fue como lo hice usando React Router 6.4:
npm install react-router-dom
Luego se crea el Router de la siguiente manera en App.js:
import React from 'react'
import { GlobalStyle } from './styles/GlobalStyle'
import { Logo } from './components/Logo'
import { PhotoCardWithQuery } from './containers/PhotoCardWithQuery'
import { Home } from './pages/Home'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
const router = createBrowserRouter(([
{
path: '/',
element: <Home />
},
{
path: '/pet/:id',
element: <Home />
}
]))
export const App = () => {
const urlParams = new window.URLSearchParams(window.location.search)
const detailId = urlParams.get('detail')
return (
<div>
<GlobalStyle />
<Logo />
{
detailId
? <PhotoCardWithQuery id={detailId} />
: <RouterProvider router={router} />
}
</div>
)
}
y finalmente en Home.js:
import React from 'react'
import { useParams } from 'react-router-dom'
import { ListOfCategories } from '../components/ListOfCategories'
import { ListOfPhotoCards } from '../components/ListOfPhotoCards'
export function Home () {
const { id } = useParams()
return (
<>
<ListOfCategories />
<ListOfPhotoCards categoryId={id} />
</>
)
}import React from 'react'
import { useParams } from 'react-router-dom'
import { ListOfCategories } from '../components/ListOfCategories'
import { ListOfPhotoCards } from '../components/ListOfPhotoCards'
export function Home () {
const { id } = useParams()
return (
<>
<ListOfCategories />
<ListOfPhotoCards categoryId={id} />
</>
)
}
Un consejo para cuando tengan muchas rutas, crear una carpeta en el proyecto con nombre /routes dentro un archivo index.js con las rutas para poder importarlo donde sea necesario y puedas cambiar las rutas de forma mas fácil.
export default {
home: '/'
}
ya se fusionaron??
a la fecha 24-05-2021
la version actual de react es @17.x y no es compatible con la version de @reach/react por eso no deja instalar la dependencia a menos que lo forcemos.
npm install @reach/router --force
esto nos permite instalar la dependencia aunque tenga advertencias, para luego actualizar la version de @reach/router
He tenido problemas con el renderizado de las fotos porque al cambiar la url no me estan mostrando los componentes. Asi que decidi usar el link en lugar del href y asi evitar la renderizacion y funciona super!
Notas
React Router y Reach Router serán fusionados a futuro y predominará las características de Reach Router
Es una lastima que casi cada clase este desactualizada.
React Router V6 y Reach Router V2 son lo mismo hoy en día, agosto 2022
Hola, para marzo del 2023 haremos lo siguiente:
Instalamos react-router-dom
npm i react-router-dom
Luego escribimos el siguiente codigo:
ListOfCategories
const renderList = (fixed)=>(
<List fixed={fixed}>
{
loading?
[1,2,3,,4,5,6].map(category=><Item key={category}><CategorySkeleton /></Item>):
categories.map(category=><Item key={category.id}><Category {...category} path={`/pet/${category.id}`} /></Item>)
}
</List>
)
return (
<>
{renderList()}
{showFixed && renderList(true)}
</>
)
App.js
import React from 'react'
import { Route, BrowserRouter, Routes } from 'react-router-dom'
import { GlobalStyle } from './styles/GlobalStyles'
// import { ListOfPhotoCards } from './components/ListOfPhotoCards'
import { Logo } from './components/Logo'
import { PhotoCardWithQuery } from './container/PhotoCardWithQuery'
import { Home } from './pages/Home'
export const App = () => {
const urlParams = new URLSearchParams(location.search);
const detailId = urlParams.get('detail');
return (
<>
<GlobalStyle />
<Logo />
{
detailId?
<PhotoCardWithQuery id={detailId} />:(
<BrowserRouter>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/pet/:id' element={<Home />} />
</Routes>
</BrowserRouter>
)
}
</>
)
}
Home.js
import React from 'react'
import { useParams } from 'react-router-dom'
import { ListOfCategories } from '../components/ListOfCategories'
import { ListOfPhotoCardsContainer } from '../container/ListOfPhotoCardsContainer'
export const Home = ()=>{
const params = useParams();
console.log(params)
return (
<>
<ListOfCategories />
<ListOfPhotoCardsContainer categoryId={params.id} />
</>
)
}
Hoy dia tenemos React Router 6, algunos cambios respecto al 5, me parece que se simplifico
Está muy top conocer Reach Router, pero creo que ya que se unieron Reach Router y React Router deberían crear un curso nievo de React Router con todas las novedades que supone su unión con Reach Router
Dos recomendaciones para los que no les aparece las fotos de las categorías correspondientes.
export const Home = (path) => {
return (
<>
<ListOfCategories />
<ListOfPhotoCards categoryId={path.id}/>
</>
)
}
export const ListOfPhotoCards = ({ categoryId }) => {
return (
<Query query={GET_PHOTOS} variables={{categoryId}}>
{
({data = {}}) => {
return <ListOfPhotoCardComponent {...data}/>
}
}
</Query>
)
}
Hola, les dejo el avance de mi proyecto hecho en Nextjs:
https://github.com/danyel117/petgram-platzi/tree/paginafotos
Estoy intentando instalar Reach Router pero me sale el siguiente error… alguien? por el momento lo instalaré con el --force
Hola! a mi no me esta renderizando las fotos por categorias, esto he tratado de hacer.
Una consulta, intente agregarle un Favicon y no me funciono, supongo que tengo que hacer alguna configuracion con webpack en vista de la que se hizo en este tutorial, que deberia hacer para agregar un favicon?
Cuidado en el orden en las que bajan las props, parece que no es lo mismo
<Category {...category} path={`/pet/${category.id}`} />
Que
<Category path={`/pet/${category.id}`} {...category} />
Reach Router; no sabía que lo necesitaba 🤯
Reach Router es una versión simplificada y mejor optimizada de React Router, su creador es Ryan Florence el mismo creador de React Router. Se anunció que los dos paquetes se iban a unir, pero su API se va a parecer más a Reach Router.
Según eso siempre que se use Reach hay que cambiar el webpack? No queda para nada claro, pero supongo que no por lo que he visto en otros tutoriales.
Marzo 2023
Utilizando react-router-dom
Dentro del elemento BrowserRouter tenía definidas mis rutas. Aún así el router no era capaz de servírmelas y es por nuestra configuración custom de webpack. Tuve que añadir lo siguiente, una fallback para que cualquier otra ruta que se sirviera, apuntase siempre a nuestra raíz. Desde ahí, esta sería redirigida correctamente por el router.
La diferencia esta en output.publicPath y en devServer
webpack.config.js
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
output: {
filename: 'app.bundle.js',
publicPath: '/'
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
}
}
]
},
devServer: {
historyApiFallback: true
}
}
el mejor profe ever ❤️
Con este código hice funcionar tuve que consultar la documentación para hacer funcionar:
App.js
import React from "react";
import { BrowserRouter, Route,Routes,Switch } from 'react-router-dom';
import { GlobalStyle } from "./components/styles/GlobalStyles";
import { Logo } from "./components/Logo";
import { PhotoCardWithQuery } from "./container/PhotoCardWithQuery";
import { Home } from "./pages/Home";
const App=()=>{
const urlParams = new window.URLSearchParams(window.location.search)
const detailId = urlParams.get('detail')
console.log(detailId)
return (
<div>
<GlobalStyle/>
<Logo/>
{
detailId?
<PhotoCardWithQuery id={detailId}/>
:
(
<Routes>
<Route path="/" element={<Home />} />
<Route path="/pet/:id" element={<Home />} />
</Routes>
/*<BrowserRouter>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/pet/:id' element={<Home />} />
</Routes>
</BrowserRouter>*/
)
}
</div>
);
}
export default App;
src/index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import { BrowserRouter } from 'react-router-dom'
import {
ApolloClient,
InMemoryCache,
ApolloProvider
} from '@apollo/client'
const client=new ApolloClient(
{
uri:"https://petgram-server-jcamacaro-camacaro.vercel.app/graphql",
cache: new InMemoryCache()
}
)
const container = document.getElementById("app");
const root = createRoot(container);
root.render(
<React.StrictMode>
<ApolloProvider client={client}>
<BrowserRouter>
<App/>
</BrowserRouter>
</ApolloProvider>
</React.StrictMode>
);
Category/index.js
import React from "react";
import { Anchor,Image } from "./style";
const DEFAULT_IMAGE='https://imgur.com/dJa0Hpl.jpg';
export const Category=({cover=DEFAULT_IMAGE,path,emoji='?'})=>(
<Anchor to={path} >
<Image src={cover}/>
{emoji}
</Anchor>
);
Category/style.js
import styled from "styled-components";
import {Link} from "react-router-dom";
export const Anchor=styled(Link)`
display:flex;
flex-direction:column;
text-align: center;
`
export const Image=styled.img`
border: 1px solid #ddd;
box-shadow: 0px 10px 14px rgb(0,0,0,.2);
border-radius: 50%;
height: auto;
overflow: hidden;
object-fit: cover;
height: 75px;
width: 75px;
`
Reach y React Router se uniran en una sola libreria en un futuro.
https://reacttraining.com/blog/reach-react-router-future/
Para los que estén usando Next Js, mi solución fue la siguiente.
import ListOfCategories from '@components/ListCat'
import ListOfPhotoCards from '@components/ListPhoto'
import Logo from '@components/Logo'
export default function Homepage({id}) {
return (
<>
<Logo />
<ListOfCategories />
<ListOfPhotoCards categoryId={id}/>
</>
)
}
import { useRouter } from 'next/router'
import PhotoCardWithQuery from '@components/PhotoCardWithQuery'
import Homepage from '@components/Homepage'
export default function Home() {
const router = useRouter()
const detailId = router.query.detail
return (
<div>
{
detailId
? <PhotoCardWithQuery id={detailId} />
: <Homepage />
}
</div>
)
}
import Homepage from '@components/Homepage'
import { useRouter } from 'next/router'
export default function Pet(){
const router = useRouter()
const id = router.query.id
return (
<Homepage id={id}/>
)
}
[...]
export default function Category({ cover = DEFAULT_IMAGE, emoji = '?', id}) {
return (
<Link href={`/pets/${id}`} passHref>
<Anchor>
<Image src={cover} alt={emoji} />
<span>{emoji}</span>
</Anchor>
</Link>
)
}
Por si alguno tiene problemas al dia de hoy para renderizar las categorias según su conrrespondiente categoryId, les recomiendo el uso de useParams
El código quedaria así:
**En el Home.js**
import React, { Fragment } from 'react'
import { ListOfCategories } from './../components/ListOfCategories'
import { ListOfPhotoCards } from './../components/ListOfPhotoCards'
import { useParams } from 'react-router-dom'
export const Home = () => {
const { id } = useParams();
return (
<Fragment>
<ListOfCategories />
<ListOfPhotoCards categoryId={id} />
</Fragment>
)
}
**En el App.js**
import React from 'react'
import { GlobalStyles } from './styles/GlobalStyles'
import { Logo } from './components/Logo'
import { PhotoCardWhitQuery } from './container/PhotoCardWhitQuery'
import { Home } from './pages/Home'
import { BrowserRouter, Route, Routes } from "react-router-dom";
export const App = () => {
const urlParams = new URLSearchParams(document.location.search);
const detailId = urlParams.get("detail")
return (
<BrowserRouter>
<div>
<GlobalStyles />
<Logo />
{
detailId
? <PhotoCardWhitQuery id={detailId} />
:
<Routes>
<Route path='/' element={<Home />} />
<Route path='/pet/:id' element={<Home />} />
</Routes>
}
</div>
</BrowserRouter>
)
}
import React from 'react'
import ReactDOM from 'react-dom'
import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
const client = new ApolloClient({
uri: 'https://petgram-server-xsr.vercel.app/graphql',
cache: new InMemoryCache()
})
ReactDOM.render(
<ApolloProvider client={client}>
<BrowserRouter>
<App />
</BrowserRouter>
</ApolloProvider>
, document.getElementById('app'))
import React from 'react'
import { Routes, Route } from 'react-router-dom'
import { GlobalStyles } from './styles/GlobalStyles'
import { Logo } from './components/Logo'
import { PhotoCardWithQuery } from './containers/PhotoCardWithQuery'
import { Home } from './pages/Home'
const App = () => {
const urlParams = new URLSearchParams(window.location.search)
const detaild = urlParams.get('detail')
return (
<>
<GlobalStyles />
<Logo />
{
detaild
? <PhotoCardWithQuery id={detaild} />
: <Routes>
<Route path='/' element={<Home />} />
<Route path='pet/:id' element={<Home />} />
</Routes>
}
</>
)
}
export default App
import React from 'react'
import { useParams } from 'react-router-dom'
import { ListOfCategories } from '../components/ListOfCategories'
import { ListOfPhotoCards } from '../components/ListOfPhotoCards'
export const Home = () => {
const { id } = useParams()
return (
<><ListOfCategories /><ListOfPhotoCards categoryId={id} /></>
)
}
Vengo del futuro y midu tuvo razón, al final la versión 6 de React Router se parece más a Reach Router que a la versión 5 de React Router.
https://reactrouter.com/docs/en/v6/getting-started/installation
npm install react-router-[email protected]6
más o menos así funciona react routes. v6
Hola compañeros del futuro. Este comentario es del 5 de noviembre de 2021
Después de pelearme un buen rato con el tema de las rutas para que funcionara.
Ya ambas dependencias son una sola. Y se ha actualizado, hice el ejercicio usando BrowserRouter, Routes y Route que vienen la dependencia “react-router-dom” estoy usando la versión 6.0.0 el cual ha cambiado varias cosas.
npm install react-router-dom
Trate de usar “switch” para poder usar las rutas pero para esta versión de la dependencia no me lo reconocía, investigando un poco pues al parecer no funciona en esta nueva versión https://stackoverflow.com/questions/67687254/attempted-import-error-switch-is-not-exported-from-react-router
Así que el codigo me quedo de la siguiente manera:
App.jsx
import React from 'react'
import { Logo } from './components/Logo'
import { PhotoCardWithQuery } from './container/PhotoCardWithQuery'
import { Home } from './pages/Home'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { GlobalStyle } from './components/styles/GlobalStyles'
const App = () => {
const urlParams = new window.URLSearchParams(window.location.search) // parametro es la query stream de la barra de direcciones
const detailId = urlParams.get('detail')
console.log('detail' + detailId)
const categoryId = urlParams.get('pet')
console.log(typeof (categoryId))
return (
<BrowserRouter>
<GlobalStyle />
<Logo />
<Routes>
{
detailId && <Route path='/' element={<PhotoCardWithQuery id={detailId} />} />
}
{
categoryId && <Route path='/' element={<Home id={categoryId} />} />
}
<Route exact path='/' element={<Home />} />
</Routes>
</BrowserRouter>
)
}
export { App }
Home.jsx
import React from 'react'
import { ListOfCategories } from '../components/ListOfCategories'
import { ListOfPhotoCardsComponent } from '../components/ListOfPhotoCardsComponent'
const Home = (path) => {
console.log('path in home ' + path)
return (
<>
<ListOfCategories />
<ListOfPhotoCardsComponent categoryId={path.id} />
</>
)
}
export { Home }
ListOfCategories
import React, { useState, useEffect } from 'react'
import { Category } from './Category'
import { List, Item } from './styles/stylesListCategories'
// import { categories as mockCategories } from '../../api/db.json'
function useCategoriesData () {
const [categories, setCategories] = React.useState([])
const [loading, setLoading] = React.useState(false)
useEffect(() => {
setLoading(true)
fetch('https://petgramapionedrako.vercel.app/categories')
.then(res => res.json())
.then(response => {
setCategories(response)
setLoading(false)
}
)
}, [])
return { categories, loading }
}
const ListOfCategories = () => {
const { categories, loading } = useCategoriesData()
const [showFixed, setShowFixed] = useState(false)
useEffect(() => {
const onScroll = e => {
const newShowFixed = window.scrollY > 200
showFixed !== newShowFixed && setShowFixed(newShowFixed)
}
document.addEventListener('scroll', onScroll)
return () => document.removeEventListener('scroll', onScroll)
}, [showFixed])
const renderList = (fixed) => (
<List fixed={fixed}>
{
loading
? <Item key='loading'><Category /></Item>
: categories.map(category =>
<Item key={category.id}>
<Category {...category} path={`/?pet=${category.id}`} />
</Item>)
}
</List>
)
return (
<>
{renderList()}
{showFixed && renderList(true)}
</>
)
}
export { ListOfCategories }
El repositorio lo tengo aquí 😄
https://github.com/onedrako/petstagram
Para esta clase el commit es el “Rutas funcionando para categorías” o el f8a5ef74f66ae76b621f6eba6c2007c29e682fc7
Si tienen alguna idea de como mejorar el codigo es re bien recibida , me rompí la cabeza para esto pero se que hay mejores soluciones ahi afuera 😄
A dia de hoy a cambiado todo el manejo de rutas les dejo mi poarte de como lo hice yo
en el App.tsx
export const App: FC = () => {
const urlParams = new window.URLSearchParams(window.location.search);
const detailId = urlParams.get("detail");
console.log(detailId);
return (
<Router>
<div>
<GlobalStyled />
<Logo />
{(detailId && <PhotoCardQuery id={parseInt(detailId)} />) || (
<Switch>
<Route exact path="/" component={Home} />
<Route path="/pet/:id" component={Home} />
</Switch>
)}
</div>
</Router>
);
};
y en el Home.tsx
import React, { FC } from "react";
import { ListCategories } from "../components/ListCategories";
import { ListPhotoCards } from "../components/ListPhotoCards";
import { useParams } from "react-router-dom";
interface Props {
id: string
}
export const Home: FC = () => {
const { id } = useParams<Props>();
return (
<>
<ListCategories />
<ListPhotoCards categoryId={parseInt(id) } />
</>
);
};
Otra dependencia bastante minimalista para el manejo de las rutas es Wouter, solo pesa 1.6kb.
Creo que no la vi en los comentarios, así que la dejo por aquí por si a alguien le interesa.
https://www.npmjs.com/package/wouter
https://bundlephobia.com/package/[email protected]
jh
Es bueno entender nuevas herramientas, la bondad de react, el poder crear e implementar mejoras tanto en código como en librerías
La manera de acceder a las variable que tenemos en las rutas es mucho mas sencilla que en react router.
Me sale un error desde el primer cambio:
Home.js:11 Uncaught ReferenceError: detailId is not defined
at Home (Home.js:11)
at renderWithHooks (react-dom.development.js:16260)
at mountIndeterminateComponent (react-dom.development.js:18794)
at beginWork$1 (react-dom.development.js:20162)
at HTMLUnknownElement.callCallback (react-dom.development.js:336)
at Object.invokeGuardedCallbackDev (react-dom.development.js:385)
at invokeGuardedCallback (react-dom.development.js:440)
at beginWork$$1 (react-dom.development.js:25780)
at performUnitOfWork (react-dom.development.js:24698)
at workLoopSync (react-dom.development.js:24671)
este curso esta bien pro gracias!!
Excelente, me gusta cuando simplifican las cosas
Esto fue mágico
Gracias!!!
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?
o inicia sesión.