Next.js Redirigir desde / a otra página

15

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 path === / redirect to / 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>
Arturo
fuente
1
cuando quieres que ocurra la redirección?
Nico
@ NicolòCozzani, una vez que el usuario carga una página. Y después de eso, determine si url === / redirect to / hello-nextjs
Arthur

Respuestas:

23

En next.jspuede redirigir después de cargar la página usando Routerej:

import Router from 'next/router'

componentDidMount(){
    const {pathname} = Router
    if(pathname == '/' ){
       Router.push('/hello-nextjs')
    }
}

O con ganchos:

import React, { useEffect } from "react";
...
useEffect(() => {
   const {pathname} = Router
   if(pathname == '/' ){
       Router.push('/hello-nextjs')
   }
 });
Nico
fuente
¿Cómo hago con ganchos React?
Tessaracter
Sin usar las clases
Tessaracter
2
Respuesta de @Tessaracter actualizada
Nico
2
¿Qué hay de SSR? La página inicial está parpadeando con este enfoque
Eric Burel
@EricBurel, el OP claramente preguntó "Una vez que el usuario carga una página" por cierto revise esto github.com/zeit/next.js/issues/649
Nico
16

Hay tres enfoques.

1. Redireccionar eventos o funciones:

import Router from 'next/router';

<button type="button" onClick={() => Router.push('/myroute')} />

2. Redireccionar con ganchos:

import Router , {useRouter}  from 'next/router';

const router = useRouter()

<button type="button" onClick={() => router.push('/myroute')} />

3. Redireccionar con enlace:

según los documentos de Nextjs, la <a>etiqueta 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 servidor que es asPath. En todos los enfoques descritos, puede agregar asPath para redirigir tanto el cliente como el servidor.

Afsanefda
fuente
¡Hola! Puedes ver mi solución
Arthur
Este es un enfoque imperativo. Está bien redirigir en la acción del usuario, pero no en función de una condición en la carga de la página como se indica en la pregunta.
Eric Burel
¡No entendí lo que querías decir!
Afsanefda
La pregunta es sobre la redirección automática dependiendo del nombre de ruta actual de la ruta. Sus respuestas son válidas pero no aplicables en este contexto: todas requieren un clic del usuario.
Eric Burel
@EricBurel, sí, esto no es lo que quería, esta respuesta no resuelve mi pregunta
Arthur
3

La respuesta de @ Nico resuelve el problema cuando estás usando clases.

Si está utilizando una función que 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.

Tessaracter
fuente
Este problema describe lo que quería como resultado
Arthur
@Arthur. Ah, pero tu pregunta no lo dice. La respuesta de @Nico y la mía es exactamente la misma y es un sustituto de la <Switch>que está utilizando React-router. Even <Switch>no proporciona ningún código de estado 303, 302. Solo redirecciona
Tessaracter
Bueno, creo que lo discutimos aquí también. Me acabo de dar cuenta de que NextJS no establece ningún código de estado. github.com/zeit/next.js/issues/9443
Tessaracter
Por favor, elimine las clases. No sirve de nada aquí.
Pushp Singh
3

Ejemplo semioficial

Los with-cookie-authejemplos redirigen en getInitialProps. No estoy seguro de si es un patrón válido o no, 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()
  }
}

Maneja tanto el lado del servidor como el lado del cliente. La fetchllamada es la que realmente obtiene el token de autenticación, es posible que desee encapsular esto en una función separada.

Lo que recomendaría en su lugar

 1. Redireccionar en el render del lado del servidor (evitar flash durante SSR)

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 };
  };
 2. Redireccionar en componentDidMount (útil cuando SSR está desactivado, por ejemplo, en modo estático)

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 solo del cliente

Eric Burel
fuente
1

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}/>
  }
}
Arturo
fuente
2
Esta no debería ser la respuesta aceptada. De acuerdo con este github.com/zeit/next.js/issues/4931#issuecomment-512787861 no debe redirigir getInitialProps. @Afsanefda debería ser la respuesta aceptada. Y también está utilizando next.js, no necesita un enrutador de reacción para organizar las rutas. Siguiente ya maneja eso por defecto.
Rotimi-best
3
@ rotimi-best, por lo que recuerdo, tomé este código del ejemplo next.js. Además, no utilicé un router de reacción, se presentó como un ejemplo de lo que quería obtener
Arthur,
2
Esta es una respuesta válida pero solo con SSR. No se redirigirá en aplicaciones estáticas. Editar: en realidad agregará Router.push, sin embargo, el lado del cliente Router.pushdebería entrar en los métodos del ciclo de vida de los componentes en su lugar
Eric Burel
1

He implementado esta funcionalidad en mi Next.JSaplicación definiendo una página raíz que redirige al lado del servidor y al 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;
BruceHill
fuente