Soy nuevo en Next.js y me pregunto cómo redirigir desde la página de inicio ( / ) a /hello-nextjs, por ejemplo. Una vez que el usuario carga una página y luego determina si la ruta === / redirigir a /hello-nextjs
En react-router hacemos algo como:
<Switch> <Route path="/hello-nextjs" exact component={HelloNextjs} /> <Redirect to="/hello-nextjs" /> // or <Route path="/" exact render={() => <Redirect to="/hello-nextjs" />} /> </Switch>Primero, debe evaluar si necesita redirección del lado del cliente (dentro de React), redirección del lado del servidor (respuesta HTTP 301) o redirección del lado del servidor + autenticación (respuesta HTTP 301 pero también tener alguna lógica para verificar la autenticación) .
Esta es la respuesta más completa que pude escribir. Pero, en la mayoría de los escenarios, no necesita nada de esto. Simplemente redirija como lo haría en cualquier aplicación React. Prefiere las redirecciones del lado del cliente primero. Simplemente usando useEffect + router.push , y eso es todo.
La redirección del lado del servidor es tentadora, en particular cuando desea "asegurar" páginas privadas, pero debe evaluar si realmente las necesita. Por lo general, no lo haces. Inducen una complejidad inesperada, como administrar el token de autenticación y el token de actualización. En su lugar, es posible que desee agregar un servidor de puerta de enlace, un proxy inverso o cualquier servidor inicial a su arquitectura, por ejemplo, para manejar ese tipo de comprobaciones.
Tenga en cuenta que Next.js es solo una aplicación React, y el uso de funciones avanzadas de Next.js como SSR tiene un costo que debe justificarse en su contexto.
Hola, aquí hay un componente de ejemplo que funciona en todos los escenarios:
Vulcan next starter withAcceso privado
La respuesta es enorme, lo siento si de alguna manera rompo las reglas de SO, pero no quiero pegar un código de 180 líneas. No existe un patrón fácil para manejar la redirección en Next, si desea admitir SSR y exportación estática.
Cada uno de los siguientes escenarios necesita un patrón específico:
Al momento de escribir (Next 9.4), debe usar getInitialProps , no getServerSideProps , de lo contrario, perderá la capacidad de realizar next export .
Como indicó @Arthur en los comentarios, 9.5 también incluye las posibilidades de configurar redireccionamientos en next.config.js . Las limitaciones de esta función aún no me quedan claras, pero parecen ser redirecciones globales, por ejemplo, cuando necesita mover una página o permitir el acceso solo durante un período limitado. Por lo tanto, no están destinados a manejar la autenticación, por ejemplo, porque no parecen tener acceso al contexto de la solicitud. De nuevo, por confirmar.
Esta solución es específica para la redirección en función de la autenticación.
Los patrones de autenticación ahora están documentados
No me gusta la autenticación de getServerSideProps porque, en mi opinión, es demasiado tarde y puede ser difícil de configurar con patrones avanzados, como el manejo del token de actualización. Pero esa es la solución oficial.
También puede consultar el enfoque documentado en este ticket en función de cómo funciona el panel de control de Vercel (en el momento de escribir este artículo), que evita la aparición de contenido no autenticado.
Next 10.2 introduce reescrituras basadas en encabezados y cookies. Esa es una excelente manera de redirigir del lado del servidor, en función de la presencia de una cookie o encabezado de autenticación.
Sin embargo, tenga en cuenta que esta no es una redirección segura . El usuario puede modificar sus encabezados de solicitud con un token falso. Todavía necesita una puerta de enlace, un proxy inverso o un servidor inicial para verificar realmente la validez del token y configurar correctamente los encabezados.
Editar: tenga en cuenta que la URL no cambiará. Una reescritura apunta una URL a una página existente de su aplicación, sin cambiar la URL => le permite tener URL "virtuales".
Ejemplo de caso de uso: imagine que tiene una página src/contact.tsx , que está traducida y configurada para la redirección i18n. Puede traducir el nombre de la página ("contacto") reescribiendo /de/kontact a /de/contact .
Ahora, el middleware le brinda control total sobre las redirecciones del lado del servidor.
Sin embargo, tenga en cuenta nuevamente que la mayoría de las veces una redirección y verificación del lado del cliente es suficiente.
Los ejemplos with-cookie-auth redirigen en getInitialProps . No estoy seguro de si es un patrón válido o no todavía, pero aquí está el código:
Profile.getInitialProps = async ctx => { const { token } = nextCookie(ctx) const apiUrl = getHost(ctx.req) + '/api/profile' const redirectOnError = () => typeof window !== 'undefined' ? Router.push('/login') : ctx.res.writeHead(302, { Location: '/login' }).end() try { const response = await fetch(apiUrl, { credentials: 'include', headers: { Authorization: JSON.stringify({ token }), }, }) if (response.ok) { const js = await response.json() console.log('js', js) return js } else { // https://github.com/developit/unfetch#caveats return await redirectOnError() } } catch (error) { // Implementation or Network error return redirectOnError() } } Se encarga tanto del lado del servidor como del lado del cliente. La llamada de fetch es la que realmente obtiene el token de autenticación, es posible que desee encapsular esto en una función separada.
Este es el caso más común. Desea redirigir en este punto para evitar que la página inicial parpadee en la primera carga.
MyApp.getInitialProps = async appContext => { const currentUser = await getCurrentUser(); // define this beforehand const appProps = await App.getInitialProps(appContext); // check that we are in SSR mode (NOT static and NOT client-side) if (typeof window === "undefined" && appContext.ctx.res.writeHead) { if (!currentUser && !isPublicRoute(appContext.router.pathname)) { appContext.ctx.res.writeHead(302, { Location: "/account/login" }); appContext.ctx.res.end(); } } return { ...appProps, currentUser }; };Esta es una alternativa para la representación del lado del cliente.
componentDidMount() { const { currentUser, router } = this.props; if (!currentUser && !isPublicRoute(router.pathname)) { Router.push("/account/login"); } }No pude evitar mostrar la página inicial en modo estático, agregue este punto, porque no puede redirigir durante la compilación estática, pero parece mejor que los enfoques habituales. Intentaré editar a medida que avance.
El ejemplo completo está aquí.
Problema relevante, que lamentablemente termina con una respuesta exclusiva para el cliente
La respuesta de @Nico resuelve el problema cuando estás usando clases.
Si está utilizando la función, no puede usar componentDidMount . En su lugar, puede usar React Hooks useEffect .
import React, {useEffect} from 'react'; export default function App() { const classes = useStyles(); useEffect(() => { const {pathname} = Router if(pathname == '/' ){ Router.push('/templates/mainpage1') } } , []); return ( null ) }En 2019, React introdujo ganchos. que son mucho más rápidos y eficientes que las clases.
Implementé esta funcionalidad en mi aplicación Next.JS definiendo una página raíz que redirige el lado del servidor y el lado del cliente. Aquí está el código para la página raíz:
import { useEffect } from "react"; import Router from "next/router"; const redirectTo = "/hello-nextjs"; const RootPage = () => { useEffect(() => Router.push(redirectTo)); return null; }; RootPage.getInitialProps = (ctx) => { if (ctx.req) { ctx.res.writeHead(302, { Location: redirectTo }); ctx.res.end(); } }; export default RootPage;Aquí hay 2 ejemplos de nivel de copiar y pegar: uno para el navegador y otro para el servidor.
https://dev.to/justincy/redireccionamiento-del-lado-del-cliente-y-del-servidor-en-next-js-3ile
Digamos que desea redirigir desde su raíz (/) a una página llamada inicio: (/inicio)
En su archivo de índice principal, pegue esto:
Lado del cliente
import { useRouter } from 'next/router' function RedirectPage() { const router = useRouter() // Make sure we're in the browser if (typeof window !== 'undefined') { router.push('/home') } } export default RedirectPageLado del servidor
import { useRouter } from 'next/router' function RedirectPage({ ctx }) { const router = useRouter() // Make sure we're in the browser if (typeof window !== 'undefined') { router.push('/home'); return; } } RedirectPage.getInitialProps = ctx => { // We check for ctx.res to make sure we're on the server. if (ctx.res) { ctx.res.writeHead(302, { Location: '/home' }); ctx.res.end(); } return { }; } export default RedirectPageSi su intención es asegurarse de que su aplicación se ejecute como un SPA y desee interceptar un nombre de ruta entrante no válido (o válido), que el usuario pegó en la barra de direcciones, aquí hay una forma rápida/intrincada de hacerlo.
Asume que tus caminos son,
enum ERoutes { HOME = '/', ABOUT = '/about', CONTACT = '/contact' } Agregue una página de _error personalizada si aún no tiene una, y agréguele esto:
import React from 'react'; import { NextPage } from 'next'; import { useDispatch } from 'react-redux'; import { useRouter } from 'next/router'; const Error: NextPage = () => { const { asPath, push } = useRouter(); const dispatch = useDispatch(); React.useEffect(() => { const routeValid = Object.values(ERoutes).includes(asPath); if (routeValid) { // do some stuff, such as assigning redux state to then render SPA content in your index page } else { // you can either continue to render this _error component, or redirect to your index page, // where you may have your own error component that is displayed based on your app state. // In my case, I always redirect to '/' (as you can see below, where I push('/'), but before doing so, // I dispatch relevant redux actions based on the situation } // I redirect to root always, but you can redirect only if routeValid === true push('/'); }, []); return ( <div>Error because '{asPath}' does not exist</div> ); }; export default Error;Actualización: Next.js >= 12
Ahora puede hacer redirecciones usando middleware , cree un archivo _middleware.js dentro de la carpeta de páginas (o cualquier subcarpeta dentro de las páginas)
import { NextResponse, NextRequest } from 'next/server' export async function middleware(req, ev) { const { pathname } = req.nextUrl if (pathname == '/') { return NextResponse.redirect('/hello-nextjs') } return NextResponse.next() }Actualización: Next.js >= 10
Desde Next.js 10 puede hacer redireccionamientos del lado del servidor (consulte a continuación los redireccionamientos del lado del cliente) con una clave de redirect dentro getServerSideProps o getStaticProps :
export async function getServerSideProps(context) { const res = await fetch(`https://.../data`) const data = await res.json() // or use context.resolvedUrl for conditional redirect // if(context.resolvedUrl == "/") if (!data) { return { redirect: { destination: '/hello-nextjs', permanent: false, }, } } return { props: {}, // will be passed to the page component as props } } Nota : El uso getServerSideProps obligará a la aplicación a SSR, tampoco se admite la redirección en el momento de la compilación. Si se conocen las redirecciones en el momento de la compilación, puede agregarlas dentro de next.config.js
En next.js puede redirigir después de cargar la página usando Router ex:
import Router from 'next/router' componentDidMount(){ const {pathname} = Router if(pathname == '/' ){ Router.push('/hello-nextjs') } }O con ganchos:
import React, { useEffect } from "react"; import Router from 'next/router' ... useEffect(() => { const {pathname} = Router if(pathname == '/' ){ Router.push('/hello-nextjs') } });Si desea evitar el parpadeo antes de la redirección, puede usar un truco simple:
import React, { useEffect,useState } from "react"; import Router from 'next/router' const myPage = ()=>{ const [loaded,setLoaded] = useState(false) useEffect(() => { const {pathname} = Router // conditional redirect if(pathname == '/' ){ // with router.push the page may be added to history // the browser on history back will go back to this page and then forward again to the redirected page // you can prevent this behaviour using location.replace Router.push('/hello-nextjs') //location.replace("/hello-nextjs") }else{ setLoaded(true) } },[]); if(!loaded){ return <div></div> //show nothing or a loader } return ( <p> You will see this page only if pathname !== "/" , <br/> </p> ) } export default myPage Diría que, en general, no es un enfoque bueno/elegante para hacer redirecciones de clientes cuando puede usar redirecciones next.config.js o incluso mejor usar la representación condicional de componentes.
He creado un repositorio simple con todos los ejemplos anteriores aquí .
Hay tres enfoques.
1. Redirigir en eventos o funciones:
import Router from 'next/router'; <button type="button" onClick={() => Router.push('/myroute')} />2. Redirigir con ganchos:
import Router , {useRouter} from 'next/router'; const router = useRouter() <button type="button" onClick={() => router.push('/myroute')} />3. Redirigir con enlace:
según los documentos de Nextjs, la etiqueta <a> es necesaria dentro del enlace para cosas como abrir en una nueva pestaña.
import Link from 'next/link'; <Link href="/myroute"> <a>myroute</a> </Link> Hay algunas otras opciones para el enrutamiento del lado del servidor que es asPath . en todos los enfoques descritos, puede agregar asPath para redirigir tanto el lado del cliente como el del servidor.
redirect-to.ts
import Router from "next/router"; export default function redirectTo( destination: any, { res, status }: any = {} ): void { if (res) { res.writeHead(status || 302, { Location: destination }); res.end(); } else if (destination[0] === "/" && destination[1] !== "/") { Router.push(destination); } else { window.location = destination; } } _app.tsx
import App, {AppContext} from 'next/app' import Router from "next/router" import React from 'react' import redirectTo from "../utils/redirect-to" export default class MyApp extends App { public static async getInitialProps({Component, ctx}: AppContext): Promise<{pageProps: {}}> { let pageProps = {}; if (Component.getInitialProps) { pageProps = await Component.getInitialProps(ctx); } if (ctx.pathname === "" || ctx.pathname === "/_error") { redirectTo("/hello-next-js", { res: ctx.res, status: 301 }); <== Redirect-To return {pageProps}; } return {pageProps}; } render() { const {Component, pageProps} = this.props; return <Component {...pageProps}/> } }Next.js 10+ nos ofrece una solución extra y elegante para hacer una redirección.
LADO DEL SERVIDOR : debe usar getServerSideProps
El siguiente ejemplo asume que tenemos alguna sesión adicional para verificar (pero puede ser cualquier cosa que desee). Si la sesión está vacía y estamos del lado del servidor ( context.res ), eso significa que el usuario no ha iniciado sesión y debemos redirigir a la página de inicio de sesión ( /login ). De otra manera, podemos pasar la session a props y redirigir al /dashboard :
import { getSession } from 'next-auth/client'; export const getServerSideProps = async (context) => { const session = await getSession(context); if(context.res && !session) { return { redirect: { permanent: false, destination: '/login' } } } return { props: { session }, redirect: { permanent: false, destination: '/dashboard' } } } LADO DEL CLIENTE : puede usar, por ejemplo useRouter hook:
import { useRouter } from 'next/router'; import { useSession } from 'next-auth/client'; const router = useRouter(); const [ session, loading ] = useSession(); if (typeof window !== 'undefined' && loading) return null; if (typeof window !== 'undefined' && !session) { router.push('/login'); } router.push('/dashboard');Más información aquí: https://github.com/vercel/next.js/discussions/14890
Válido para NextJS 9.5.0+
next.config.js module.exports = { async redirects() { return [ { source: '/team', destination: '/about', permanent: false, }, { source: "/blog", destination: "https://blog.dundermifflin.com", permanent: true, }, ]; }, };https://github.com/vercel/next.js/tree/canary/examples/redirects
En NextJs v9.5 y superior, puede configurar redireccionamientos y reescrituras en el archivo next.config.js .
Pero si usa trailingSlash: true asegúrese de que la ruta de origen termine con una barra inclinada para que coincida correctamente.
module.exports = { trailingSlash: true, async redirects() { return [ { source: '/old/:slug/', // Notice the slash at the end destination: '/new/:slug', permanent: false, }, ] }, }También debe tener en cuenta otros complementos y configuraciones que pueden afectar el enrutamiento, por ejemplo, next-images .
Documentación: https://nextjs.org/docs/api-reference/next.config.js/redirects