React Router actualizó su API pública, por eso es necesario que cambiemos como la forma en la que usamos esta librería. Para eso vamos a tomar el proyecto que hicimos y actualizarlo.
Lo primero que vamos a hacer es desinstalarlo con el comando:
npmrm -S react-router
Y luego vamos a instalar react-router-dom con el comando:
npm i -S react-router-dom@next
La razón de instalar react-router-dom y no react-router es que desde ahora React Router va a soportar una versión para aplicaciones web (-dom) tanto en el cliente como en el servidor y una versión para aplicaciones de React Native (-native). En nuestro caso nos vamos a concentrar en la versión para web.
Actualizando el servidor de render
Vamos a ir a source/server.jsx y vamos a dejar de importar react-router, en vez de eso vamos a importar:
import{StaticRouter}from'react-router-dom';
Acá podemos ver el primer cambio, en vez de importar ServerRouter ahora importamos StaticRouter y ya no necesitamos createServerRenderContext. Luego de cambiar este import vamos cambiar la siguiente línea.
const context =createServerRenderContext();
Y vamos a colocar:
const context ={};
Como vemos es simplemente crear un objeto vacío en vez de ejecutar una función. Luego tenemos que modificar donde hacemos el renderToString para usar StaticRouter quedando algo así:
const html =renderToString(<Provider store={store}><IntlProvider locale={locale} messages={messages[locale]}><StaticRouterlocation={request.url} context={context}><Pages/></StaticRouter></IntlProvider></Provider>,);
De esta forma ya estamos haciendo el render con los nuevos componentes de React Router. Ahorat tenemos que eliminar la línea donde obteníamos el resultado del contexto.
const result = context.getResult();
Ya que el resultado va a estar directamente en el objecto context que creamos antes. De igual forma vamos a cambiar la validación de result.missed por context.url y vamos a usar este mismo context.url donde antes definíamos el Location al hacer redirect. Quedando algo similar a esto:
Un último cambio es que React Router ya nos dice si no encontró la URL (un 404) por lo que tanto la condición como el doble render que había que hacer es innecesario y podemos eliminarlos.
Actualizando nuestras rutas
Lo siguiente que vamos a actualizar es el archivo source/pages/containers/Page.jsx. Al igual que antes vamos a cambiar la línea donde importamos React Router quedando así:
import{Route,Switch,}from'react-router-dom';
Como vemos en vez de Match y Miss importamos Route y Switch. Luego en todos los lugares donde usábamos Match y Miss tenemos que usar Route quedando así:
{/* List de artículos */}<Route path="/" exact
component={Home}/>{/* Detalle de artículo */}<Route path="/post/:id" exact
component={Post}/>{/* Perfil de usuario */}<Route path="/user/:id" exact
component={Profile}/>{/* Galería de fotos */}<Route path="/gallery" exact
component={Gallery}/>{/* Error 404 */}<Route component={Error404}/>
Como vemos el prop pattern ahora se llama path y exactly es exact. El resto de props es igual. Otra cosa que vamos a hacer es envolver todos estos componente en Switch.
Este componente Switch lo que hace es que una vez una de las rutas haga render deja de verificar las otras rutas de la aplicación. Sin usar este componente React Router verificaría cada ruta definidia y si más de un componente hacía match entonces renderizaba todos esos componentes (pudiendo ser N). Switch nos evita eso completamente, solo permitiendo una ruta.
El código de nuestro componente Page quedaría algo así al final:
functionPages(){return(<main role="application"><Header/><Switch>{/* List de artículos */}<Route path="/" exact
component={Home}/>{/* Detalle de artículo */}<Route path="/post/:id" exact
component={Post}/>{/* Perfil de usuario */}<Route path="/user/:id" exact
component={Profile}/>{/* Galería de fotos */}<Route path="/gallery" exact
component={Gallery}/>{/* Error 404 */}<Route component={Error404}/></Switch></main>);}
Importando el componente Link y BrowserRouter
Lo siguiente que vamos a hacer es muy simple, en todos los lugares donde importamos Link de React Router vamos a cambiar el import y vamos a usar la siguiente línea:
import{Link}from'react-router-dom';
Simplemente es importar Link de react-router-dom. Luego vamos a ir a source/client.jsx y vamos a cambiar el import de BrowserRouter para importarlo de react-router-dom.
import{BrowserRouter}from'react-router-dom';
Con esto ya cambiamos todos los imports necesarios y estamos usando los nuevos componentes de React Router. Hay un último cambio que hacer y es cambiar un dato dentro de dos de nuestras página.
Obteniendo parámetros de la URL
En los componentes source/pages/containers/Post.jsx y source/pages/containers/Profile.jsx obteníamos un prop llamado params que era un objeto con todos los parámetros de la URL, como por ejemplo el id del post o usuario cuyo detalle estábamos viendo. Ahora para poder acceder a este datos es necesario usar un prop llamado match que posee el objeto params.
Eso significa que ahora el initialFetch de Post.jsx va a hacer el fetch de la siguiente forma:
const[ post, comments,]=awaitPromise.all([ api.posts.getSingle(this.props.match.params.id), api.posts.getComments(this.props.match.params.id),]);
Y el initialFetch de Profile.jsx va a hacerlo así:
Con esto ahora ya toda nuestra aplicación debería funcionar con la última versión de React Router sin problemas. Este tipo de casos donde una librería se actualice y cambio su API pública es algo común en el mundo de JavaScript y como desarrolladores es parte de nuestro trabajo mantenernos al tanto y actualizar nuestro código para estar al día con las últimas versiones.
No consideren esto como un problema o algo malo, sino como algo natural y hasta deseable, ya que significa que las librerías o frameworks que usemos están mejorando y evolucionando.
Hola, he actualizado, pero me quedaron algunas dudas, debido a que tuve que hacer algo un poco distinto de lo que aparece en este tutorial y en
1) Las rutas no pueden empezar con “/”, debido a que me genera mal la ruta, simplemente lo coloqué así
<Link to="about">About</Link>
2) El link a la raíz del proyecto no puede ser con “/”, lo tuve que colocar con “.”, ejemplo:
<Link to=".">Go to home</Link>
Por lo que puedo inferir, mis problemas estaban al usar el slash (/), a que se debe esta diferencia?
Hola Sergio no se porque al momento de instalar el react-router, si pongo @next me marca error en Windows.
Sin embargo si lo instalo sin el @next puedo descargarlo del npm, eso tiene algún problema o es igual de todas formas??
MUCHAS GRACIAS PROFE!!! 😃
Hola Sergio!
podrias porfavor compartir el github repo de este proyecto completo para que pueda verse como luce finalmente porfavor??? 😃
de paso tu proyecto servira como como una buena referencia para estructurar los archivos react-redux y este nuevo react-router 😃
me marca lo siguiente al intentar instalar react-router-dom
npm ERR! notarget No compatible version found: react-router-dom@next
npm ERR! notarget Valid install targets:
npm ERR! notarget 4.1.1, 4.1.0, 4.0.0, 4.0.0-beta.8, 4.0.0-beta.7, 4.0.0-beta.6, 4.0.0-beta.5, 4.0.0-beta.4, 4.0.0-beta.3, 4.0.0-beta.2, 4.0.0-beta.1, 0.0.0
npm ERR! notarget
npm ERR! notarget This is most likely not a problem with npm itself.
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn’t exist.
npm ERR! Please include the following file with any support request:
npm ERR! C:\dev\react\proyecto-ejemplo\npm-debug.log
Estas tratando de instalar una versión que no existe, prueba con
npm install --save react-router-dom
Esto instala la última versión de la librería
Muchas gracias @GOLLUM23 así si jaló el comando, saludos!
Hola, tengo el último problema, no entendí bien la última parte de “Obteniendo parámetros de la URL”, por que, qué son los “initialFetch” y “propTypes”?. Lo segundo, en la terminal me sale lo siguiente:
<code>MBP-de-Bubba:reactjs Bubba$ node built/server/index.js/Users/Bubba/Dropbox/reactjs/built/server/index.js:23782Provider,^ReferenceError:Provider is not defined
at Server.requestHandler(/Users/Bubba/Dropbox/reactjs/built/server/index.js:23782:3) at emitTwo(events.js:106:13) at Server.emit(events.js:191:7) at HTTPParser.parserOnIncoming[as onIncoming](_http_server.js:547:12) at HTTPParser.parserOnHeadersComplete(_http_common.js:99:23)MBP-de-Bubba:reactjs Bubba$
El initialFetch y los propTypes los vemos en el desarrollo del proyecto, si todavía no llegaste a esa parte te recomiendo que sigas con el proyecto usando al versión de React Router usada en el curso y luego al final hagas la actualización.
Sobre el otro error, pareciera que no importantes bien Provider de react-redux.
Yo también tengo ese mismo error, como importo el Provider 😕
Tengo este warning
C:\Users\aseguramiento23\Desktop\blog-react>node built\server\index.js
Warning: Failed prop type: Invalid prop component of type object supplied to Route, expected function.
in Route
C:\Users\aseguramiento23\Desktop\blog-react\built\server\index.js:11006
Provider,
^
ReferenceError: Provider is not defined
at Server.requestHandler (C:\Users\aseguramiento23\Desktop\blog-react\built\server\index.js:11006:5)
at emitTwo (events.js:106:13)
at Server.emit (events.js:191:7)
at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:546:12)
at HTTPParser.parserOnHeadersComplete (_http_common.js:99:23)
Hola Sergio, esto es mas una duda conceptual. Veo que haces el import npm rm -S react-router-dom usan -S a cambio de -D como lo dijiste en el inicio del curso la D se interpreta como una dependencia de desarrollo, pero por que con react-router-dom usas -S ?
El -S es para decirle que lo guarde en el package.json como una dependencia del proyecto.
y -D ?
Estoy obteniendo un error en consola. Me sale como si fuera de mi server/index.js
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.
¿Qué cosa podría ser el problema? Creo tener el código tal cuál está en el curso y he realizado estos cambios ya que no me funcionaba antes tampoco.
Revisa que hayas corregido todos los import, el error que ocurre es porque estás tratando de usar como si fuese un componente de React un valor undefined, entonces no funciona. Ese error puede ser que algún componente se esté importando mal. Por ejemplo al importar Link o StaticRouter.
Si no logras encontrarlo subí tu código a Github para poder revisarlo.
HOLA AMIGOS, ME SALE
C:\Users\sergio\Desktop\app-R>node built/server/index.js
C:\Users\sergio\Desktop\app-R\built\server\index.js:24626
_react2.default.createElement(Header, null),
^
ReferenceError: Header is not defined
at Pages (C:\Users\sergio\Desktop\app-R\built\server\index.js:24626:33)
at C:\Users\sergio\Desktop\app-R\built\server\index.js:18442:16
at measureLifeCyclePerf (C:\Users\sergio\Desktop\app-R\built\server\index.js
:18212:12)
at ReactCompositeComponentWrapper._constructComponentWithoutOwner (C:\Users
sergio\Desktop\app-R\built\server\index.js:18441:14)
at ReactCompositeComponentWrapper._constructComponent (C:\Users\sergio\Deskt
op\app-R\built\server\index.js:18416:21)
at ReactCompositeComponentWrapper.mountComponent (C:\Users\sergio\Desktop\ap
p-R\built\server\index.js:18324:21)
at Object.mountComponent (C:\Users\sergio\Desktop\app-R\built\server\index.j
s:3082:35)
at ReactCompositeComponentWrapper.performInitialMount (C:\Users\sergio\Deskt
op\app-R\built\server\index.js:18507:34)
at ReactCompositeComponentWrapper.mountComponent (C:\Users\sergio\Desktop\ap
p-R\built\server\index.js:18394:21)
at Object.mountComponent (C:\Users\sergio\Desktop\app-R\built\server\index.j
s:3082:35)
Porque veo un source/client.jsx si en el proyecto no existe ese file :thi