Redirection vers Next.js depuis / vers une autre page

15

Je suis nouveau dans Next.js et je me demande comment rediriger de la page de démarrage ( / ) vers / hello-nextjs par exemple. Une fois que l'utilisateur a chargé une page et après cela, déterminez si le chemin === / redirige vers / hello-nextjs

Dans react-router, nous faisons quelque chose comme:

<Switch>
  <Route path="/hello-nextjs" exact component={HelloNextjs} />
  <Redirect to="/hello-nextjs" /> // or <Route path="/" exact render={() => <Redirect to="/hello-nextjs" />} />
</Switch>
Arthur
la source
1
quand vous voulez que la redirection se produise?
Nico
@ NicolòCozzani, une fois que l'utilisateur a chargé une page. Et après cela, déterminez si l'url === / redirige vers / hello-nextjs
Arthur

Réponses:

23

Dans next.jsvous pouvez rediriger après le chargement de la page en utilisant Routerex:

import Router from 'next/router'

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

Ou avec des crochets:

import React, { useEffect } from "react";
...
useEffect(() => {
   const {pathname} = Router
   if(pathname == '/' ){
       Router.push('/hello-nextjs')
   }
 });
Nico
la source
Comment faire avec les crochets React ??
Tessaracter
Sans utiliser les cours
Tessaracter
2
@Tessaracter réponse mise à jour
Nico
2
Et la SSR? La page initiale clignote avec cette approche
Eric Burel
@EricBurel l'OP a clairement demandé "Une fois que l'utilisateur charge une page" btw consultez ce github.com/zeit/next.js/issues/649
Nico
16

Il existe trois approches.

1. rediriger les événements ou les fonctions:

import Router from 'next/router';

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

2. rediriger avec des crochets:

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

const router = useRouter()

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

3. rediriger avec Link:

basé sur les documents Nextjs, le <a>tag est nécessaire à l'intérieur du lien pour des choses comme ouvrir dans un nouvel onglet!

import Link from 'next/link';

<Link href="/myroute">
   <a>myroute</a>
</Link>

Il existe d'autres options pour le routage côté serveur asPath. dans toutes les approches décrites, vous pouvez ajouter asPath pour rediriger le côté client et le côté serveur.

Afsanefda
la source
Salut! Vous pouvez regarder ma solution
Arthur
Il s'agit d'une approche impérative. Il est correct de rediriger l'action de l'utilisateur, mais pas en fonction d'une condition de chargement de page comme indiqué dans la question.
Eric Burel
Je n'ai pas compris ce que tu voulais dire!?
Afsanefda
La question concerne la redirection automatique en fonction du chemin d'accès de l'itinéraire actuel. Vos réponses sont valables mais non applicables dans ce contexte: elles nécessitent toutes un clic de l'utilisateur.
Eric Burel
@EricBurel, oui, ce n'est pas ce que je voulais, cette réponse ne résout pas ma question
Arthur
3

La réponse de @ Nico résout le problème lorsque vous utilisez des classes.

Si vous utilisez une fonction que vous ne pouvez pas utiliser componentDidMount. Au lieu de cela, vous pouvez utiliser 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 a introduit des crochets. qui sont beaucoup plus rapides et efficaces que les classes.

Tessaracter
la source
Ce numéro décrit ce que je voulais en conséquence
Arthur
@Arthur. Oh, mais votre question ne le dit pas. La réponse de @Nico et de la mienne est exactement la même et remplace celle <Switch>que vous utilisez React-router. Même <Switch>ne fournit aucun code d'état 303, 302. Redirige simplement
Tessaracter
Eh bien, je pense que la discussion ici aussi. Je viens de réaliser que NextJS ne définit aucun code d'état. github.com/zeit/next.js/issues/9443
Tessaracter
Veuillez supprimer les cours. Cela ne sert à rien ici.
Pushp Singh
3

Exemple semi-officiel

Les with-cookie-authexemples redirigent vers getInitialProps. Je ne sais pas si c'est un modèle valide ou pas encore, mais voici le code:

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()
  }
}

Il gère à la fois côté serveur et côté client. L' fetchappel est celui qui obtient réellement le jeton d'authentification, vous voudrez peut-être l'encapsuler dans une fonction distincte.

Ce que je conseillerais à la place

 1. Rediriger le rendu côté serveur (éviter le flash pendant la SSR)

C'est le cas le plus courant. Vous souhaitez rediriger à ce stade pour éviter que la page initiale ne clignote lors du premier chargement.

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. Rediriger dans componentDidMount (utile lorsque SSR est désactivé, par exemple en mode statique)

Il s'agit d'un remplacement pour le rendu côté client.

  componentDidMount() {
    const { currentUser, router } = this.props;
    if (!currentUser && !isPublicRoute(router.pathname)) {
      Router.push("/account/login");
    }
  }

Je ne pouvais pas éviter de flasher la page initiale en mode statique, ajoutez ce point, car vous ne pouvez pas rediriger pendant la construction statique, mais cela semble mieux que les approches habituelles. Je vais essayer d'éditer au fur et à mesure que je progresse.

L'exemple complet est ici

Problème pertinent, qui se termine malheureusement par une réponse du client uniquement

Eric Burel
la source
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}/>
  }
}
Arthur
la source
2
Cela ne devrait pas être la réponse acceptée. Selon ce github.com/zeit/next.js/issues/4931#issuecomment-512787861, vous ne devez pas rediriger vers getInitialProps. @Afsanefda devrait être la réponse acceptée. Et vous utilisez également next.js, vous n'avez pas besoin de réagir au routeur pour organiser les itinéraires. Next gère déjà cela par défaut.
rotimi-best
3
@ rotimi-best, pour autant que je m'en souvienne, j'ai pris ce code de l'exemple next.js. De plus, je n'ai pas utilisé de réactorouter, il a été présenté comme un exemple de ce que je voulais obtenir
Arthur
2
Ceci est une réponse valide mais avec SSR uniquement. Il ne redirigera pas dans les applications statiques. Edit: en fait, vous ajouterez Router.push, mais le côté client Router.pushdevrait plutôt aller dans les méthodes de cycle de vie des composants
Eric Burel
1

J'ai implémenté cette fonctionnalité dans mon Next.JSapplication en définissant une page racine qui fait la redirection côté serveur et côté client. Voici le code de la page racine:

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
la source