Al intentar un enrutamiento superficial con una ruta dinámica en Next.js, la página se actualiza y se ignora la superficial. Parece que mucha gente está confundida acerca de esto.
Digamos que comenzamos en la página siguiente
router.push( '/post/[...slug]', '/post/2020/01/01/hello-world', { shallow: true } );
Luego enrutamos a otra publicación de blog:
router.push( '/post/[...slug]', '/post/2020/01/01/foo-bar', { shallow: true } );
Esto no desencadena un enrutamiento superficial, el navegador se actualiza, ¿por qué?
En el código base está muy claro que esta es una característica:
// If asked to change the current URL we should reload the current page // (not location.reload() but reload getInitialProps and other Next.js stuffs) // We also need to set the method = replaceState always // as this should not go into the history (That's how browsers work) // We should compare the new asPath to the current asPath, not the url if (!this.urlIsNew(as)) { method = 'replaceState' }
Puedo lograr lo mismo manualmente usando window.history.pushState()
aunque, por supuesto, sería una mala idea:
window.history.pushState({ as: '/post/2020/01/01/foo-bar', url: '/post/[...slug]', options: { shallow: true } }, '', '/post/2020/01/01/foo-bar');
Como la API interna de Next.JS podría cambiar en cualquier momento... Puede que me esté perdiendo algo... pero ¿por qué se ignora superficialmente en el caso? Parece extraño.
Bien, entonces esta respuesta se basa en mi primera respuesta (y aclaración de preguntas):
La pregunta n. ° 1 fue: This does not trigger shallow routing, the browser refreshes, why?
=> Verifique mi última respuesta para comprender cómo next.js
se ocupa de las estructuras de archivos.
#2 Si quieres lidiar con parámetros de URL ilimitados:
Tendrás que seguir esta estructura de archivos:
. ├── pages │ ├── post │ │ └──[...slug].js // or [...slug]/index.js │ ├── about.js │ └── index.js ├── public │ └── ... ├── .gitignore ├── package.json ├── package-lock.json └── README.md
[...babosa].js:
export default function Post({ post }) { return ( <div> <h1>Post is here{}</h1> {JSON.stringify(post)} </div> ); } export async function getStaticPaths() { return { paths: [ { params: { slug: ["*"] } }, ], fallback: true }; } export async function getStaticProps(context) { console.log("SLUG: ", context); const { params = [] } = context || {}; const res = await fetch(`https://api.icndb.com/jokes/${params && params.slug[0] || 3}`); const post = await res.json() return { props: { post } } }
./index.js:
import Link from 'next/link'; import Router from 'next/router' export default function Home() { const handleClick = e => { e.preventDefault(); Router.push( '/post/[...slug]', '/post/2/2/4', { shallow: true } ); } return ( <div className="container"> <div> <Link href="/about"> <a>About</a> </Link> </div> <hr /> <div> <Link href={`/post/[...slug]?slug=${2}`} as={`/post/${2}`} > <a> <span> Post: </span> </a> </Link> <hr /> <div> <button onClick={handleClick}> Push me </button> </div> </div> </div> ) }
Cualquier /post/any/url/long/will_return_slugfile
¡¡¡Otra vez!!! en next.js
debe tener cuidado con la estructura del sistema de archivos en el enrutamiento. (Como mencioné en mi última respuesta)
pages/post/[[...slug]].js will match /post, /post/a, /post/a/b, and so on.
Creo que este es el comportamiento esperado porque está enrutando a una página nueva. Si solo está cambiando los parámetros de consulta, el enrutamiento superficial debería funcionar, por ejemplo:
router.push('/?counter=10', undefined, { shallow: true })
pero estás usando parámetros de ruta
router.push( '/post/[...slug]', '/post/2020/01/01/hello-world', { shallow: true } );
Eso indica que está enrutando a una nueva página, descargará la página actual, cargará la nueva y esperará a que se obtengan los datos, aunque solicitamos hacer un enrutamiento superficial y esto se menciona en los documentos aquí Advertencias de enrutamiento superficial .
Por cierto, dices "la página se actualizó", pero router.push
no actualiza la página incluso cuando se usa sin shallow: true
. Es una aplicación de una sola página después de todo. Simplemente representa la nueva página y ejecuta getStaticProps
, getServerSideProps
o getInitialProps
.
El enrutamiento superficial le brinda la capacidad de actualizar el nombre de la ruta o los parámetros de consulta sin perder el estado, es decir, solo se cambia el estado de la ruta. Pero la condición es que debe estar en la misma página (como se muestra en la imagen de advertencias de los documentos) .
Para eso, debe pasar el segundo argumento a router.push o Router.push como indefinido. De lo contrario, se cargará una nueva página después de descargar la primera y no obtendrá el comportamiento esperado.
Me refiero a que el enrutamiento superficial ya no funcionará en términos de cambio de nombre de ruta y eso se debe a que elegimos cargar una nueva página, no solo la URL. Espero que esto ayude 😉
Ejemplo
import { useEffect } from 'react' import { useRouter } from 'next/router' // Current URL is '/' function Page() { const router = useRouter() useEffect(() => { // Always do navigations after the first render router.push('/post/[...slug]', undefined, { shallow: true }) }, []) useEffect(() => { // The pathname changed! }, [router.pathname ]) } export default Page
En realidad, según la descripción de los documentos, creo que usó esta función de push
incorrectamente. Consulte los siguientes códigos que provienen de docs :
import Router from 'next/router' Router.push(url, as, options)
Y los doctores dijeron:
url
: la URL a la que navegar. Este suele ser el nombre de una página.as
- Decorador opcional para la URL que se mostrará en el navegador. Predeterminado aurl
options
: objeto opcional con las siguientes opciones de configuración: superficial: actualice la ruta de la página actual sin volver a ejecutar getStaticProps, getServerSideProps o getInitialProps. Predeterminado a falso
Significa que debe pasar la URL exacta como primer parámetro y si desea mostrarla como nombre de decoración, pase el segundo parámetro y para el tercero simplemente pase la opción, por lo que debe escribir como se muestra a continuación:
router.push( '/post/2020/01/01/hello-world', undefined, undefined );
Para el enrutamiento poco profundo , debe usar el ejemplo exacto:
router.push('/?counter=10', undefined, { shallow: true });
De hecho, con su código, crea una nueva ruta y es inevitable que se actualice.