Next.js Przekieruj z / do innej strony

15

Jestem nowy w Next.js i zastanawiam się, jak na przykład przekierować ze strony początkowej ( / ) do / hello-nextjs . Gdy użytkownik załaduje stronę, a następnie określ, czy ścieżka === / przekieruj do / hello-nextjs

W React-Router robimy coś takiego:

<Switch>
  <Route path="/hello-nextjs" exact component={HelloNextjs} />
  <Redirect to="/hello-nextjs" /> // or <Route path="/" exact render={() => <Redirect to="/hello-nextjs" />} />
</Switch>
Artur
źródło
1
kiedy chcesz, aby nastąpiło przekierowanie?
Nico,
@ NicolòCozzani, gdy użytkownik załaduje stronę. A potem ustal, czy url === / przekieruj do / hello-nextjs
Arthur

Odpowiedzi:

23

W next.jsmożna przekierować po załadowaniu strony za pomocą Routernp .:

import Router from 'next/router'

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

Lub z hakami:

import React, { useEffect } from "react";
...
useEffect(() => {
   const {pathname} = Router
   if(pathname == '/' ){
       Router.push('/hello-nextjs')
   }
 });
Nico
źródło
Jak to zrobić z hakami React?
Tessaracter
Bez korzystania z klas
Tessaracter
2
Aktualizacja odpowiedzi @ Tessaracter
Nico
2
Co z SSR? Przy takim podejściu strona początkowa miga
Eric Burel
@EricBurel OP wyraźnie zapytał: „Gdy użytkownik załaduje stronę” btw sprawdź to github.com/zeit/next.js/issues/649
Nico
16

Istnieją trzy podejścia.

1. Przekieruj na zdarzenia lub funkcje:

import Router from 'next/router';

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

2. Przekieruj za pomocą haczyków:

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

const router = useRouter()

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

3. Przekieruj z linkiem:

na podstawie dokumentów Nextjs <a>tag jest niezbędny w łączu do takich rzeczy, jak otwieranie w nowej karcie!

import Link from 'next/link';

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

Istnieje kilka innych opcji routingu po stronie serwera asPath. we wszystkich opisanych podejściach można dodać asPath w celu przekierowania zarówno po stronie klienta, jak i serwera.

Afsanefda
źródło
Cześć! Możesz spojrzeć na moje rozwiązanie
Arthur
To jest imperatywne podejście. Przekierowywanie działań użytkownika jest w porządku, ale nie w oparciu o warunek ładowania strony, jak podano w pytaniu.
Eric Burel
Nie rozumiem, co masz na myśli !?
Afsanefda,
Pytanie dotyczy automatycznego przekierowania w zależności od bieżącej nazwy ścieżki trasy. Twoje odpowiedzi są prawidłowe, ale nie mają zastosowania w tym kontekście: wszystkie wymagają kliknięcia przez użytkownika.
Eric Burel,
@EricBurel, tak, nie tego chciałem, ta odpowiedź nie rozwiązuje mojego pytania
Arthur
3

Odpowiedź @ Nico rozwiązuje problem podczas korzystania z zajęć.

Jeśli używasz funkcji, nie możesz jej użyć componentDidMount. Zamiast tego możesz użyć React Hook 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
  )
}

W 2019 React wprowadził haki. które są znacznie szybsze i wydajniejsze niż klasy.

Tessaracter
źródło
W tym numerze opisano, czego chciałem
Arthur
@Arthur. Och, ale twoje pytanie tak nie mówi. Odpowiedzi @Nico i moje są dokładnie takie same i zastępują te <Switch>, których używasz React-router. Nawet <Switch>nie zapewnia żadnego kodu stanu 303, 302. Tylko przekierowania
Tessaracter
Cóż, myślę, że omówione tutaj również. Właśnie zdałem sobie sprawę, że NextJS nie ustawia żadnego kodu statusu. github.com/zeit/next.js/issues/9443
Tessaracter
Proszę usunąć zajęcia. Tu nie ma sensu.
Pushp Singh
3

Półoficjalny przykład

Do with-cookie-authprzykładów przekierowanie w getInitialProps. Nie jestem pewien, czy jest to prawidłowy wzorzec, czy nie, ale oto kod:

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

Obsługuje zarówno po stronie serwera, jak i klienta. fetchPołączenia jest taki, który rzeczywiście dostać token uwierzytelniający, możesz ująć to w osobnej funkcji.

Co radziłbym zamiast tego

 1. Przekieruj na renderowaniu po stronie serwera (unikaj flashowania podczas SSR)

To najczęstszy przypadek. Chcesz przekierować w tym miejscu, aby uniknąć początkowego migania strony przy pierwszym ładowaniu.

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. Przekierowanie w componentDidMount (przydatne, gdy SSR jest wyłączony, np. W trybie statycznym)

Jest to awaria renderowania po stronie klienta.

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

Nie mogłem uniknąć flashowania strony początkowej w trybie statycznym, dodaj ten punkt, ponieważ nie możesz przekierować podczas kompilacji statycznej, ale wydaje się to lepsze niż zwykłe podejścia. Spróbuję edytować, gdy będę robić postępy.

Pełny przykład jest tutaj

Odpowiedni problem, który niestety kończy się odpowiedzią klienta

Eric Burel
źródło
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}/>
  }
}
Artur
źródło
2
To nie powinna być zaakceptowana odpowiedź. Zgodnie z tym github.com/zeit/next.js/issues/4931#issuecomment-512787861 nie należy przekierowywać getInitialProps. @Afsanefda powinna być zaakceptowaną odpowiedzią. A także używasz next.js, nie musisz reagować na router, aby organizować trasy. Dalej już to domyślnie obsługuje.
rotimi-best
3
@ rotimi-best, o ile pamiętam, wziąłem ten kod z przykładu next.js. Ponadto nie użyłem routera reagującego, został przedstawiony jako przykład tego, co chciałem uzyskać
Arthur
2
To poprawna odpowiedź, ale dotyczy tylko SSR. Nie przekieruje w statycznych aplikacjach. Edycja: właściwie to dodasz Router.push, jednak strona klienta Router.pushpowinna zamiast tego przejść do metod cyklu życia komponentów
Eric Burel
1

Zaimplementowałem tę funkcję w mojej Next.JSaplikacji, definiując stronę główną, która działa po stronie serwera przekierowującego i po stronie klienta. Oto kod strony głównej:

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
źródło