Как получить предыдущий URL в nextjs

Как я могу получить предыдущий URL-адрес в nextjs? Я думал, что значения this.props.router.asPath и nextProps.router.asPath разные.

На самом деле, я хочу вызвать router.push после входа в систему. Я знаю, что router.back переходит на предыдущую страницу. Но можно перейти на другой сайт. Пользователи со стеками истории переходят на предыдущую страницу, пользователи без стеков истории переходят на / главную страницу.

import { Component } from 'react'
import App, { Container } from 'next/app';
import ErrorComponent from '@/components/error'

export default class MyApp extends App {
  render() {
    console.info(this.props)
    const { Component, pageProps, router } = this.props;
    const props = {
      ...pageProps,
      router
    }
    return (
      <ErrorBoundary>
        <Container>
          <Component {...props} />
        </Container>
      </ErrorBoundary>
    );
  }

  componentWillReceiveProps(nextProps) {
    // previous page url /contents
    console.info(this.props.router.asPath) // /about
    console.info(nextProps.router.asPath) // /about
    console.info('window.history.previous.href', window.history.previous) // undefined
  }
}

Как я могу это исправить? Или как я могу получить предыдущий URL-адрес для перемещения страницы после входа в систему?

Этот вопрос в основном дублирует: stackoverflow.com/a/65614253/10367188

dimisus 08.01.2021 15:26
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
15
1
27 886
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий

Я думаю, вы можете реализовать пользовательскую историю в глобальном состоянии.

Что-то вроде этого

_app.js

import React from 'react';
import App, { Container } from 'next/app';

class MyApp extends App {
    static async getInitialProps({ Component, ctx }) {
        let pageProps = {};

        if (Component.getInitialProps) {
            pageProps = await Component.getInitialProps(ctx);
        }

        return { pageProps };
    }

    state = {
        history: [] // keep history items in state
    };

    componentDidMount() {
        const { asPath } = this.props.router;

        // lets add initial route to `history`
        this.setState(prevState => ({ history: [...prevState.history, asPath] }));
    }

    componentDidUpdate() {
        const { history } = this.state;
        const { asPath } = this.props.router;

        // if current route (`asPath`) does not equal
        // the latest item in the history,
        // it is changed so lets save it
        if (history[history.length - 1] !== asPath) {
            this.setState(prevState => ({ history: [...prevState.history, asPath] }));
        }
    }

    render() {
        const { Component, pageProps } = this.props;

        return (
            <Container>
                <Component history = {this.state.history} {...pageProps} />
            </Container>
        );
    }
}

export default MyApp;

поэтому в ваших компонентах вы можете перемещаться по истории, где хотите

if (!history || !history.length) {
    router.push('/');
} else {
    router.push(history[history.length - 1]);
}

Надеюсь это поможет!

Вы находите Referer (то есть предыдущий URL) в контексте getServerSideProps или любых других методов выборки данных.

так как

    context.req.headers.referer  

пример в коде

    export async function getServerSideProps(context) {
      console.info(context.req.headers.referer)
    }

Чтобы сэкономить на пути туда и обратно - это действительно «реферер» с одним r посередине, а не с двумя

Oded Ben Dov 23.11.2021 13:48

Немного отличается, но связан с этим ответом. Мне нужно было, чтобы реферер в маршруте предварительного просмотра API Next.JS перенаправлял обратно к исходному рефереру при попадании на маршрут предварительного просмотра выхода, вы можете сделать это, используя request.headers.referer, где request вводится в NextApiRequest

David B 30.12.2021 15:25

Я пытался сделать что-то похожее на ответ iurii. Мой _app.js выглядит так (я пытался интегрироваться с segment.com, поэтому почувствовал необходимость)

export default class MyApp extends App {
  componentDidMount () {
    const { asPath } = this.props.router;
    this.setState(prevState => ({ history: [...prevState.history, asPath] }));

    const isBrowser = typeof window !== 'undefined';

    if (isBrowser) {
      // For the first page load
      console.info("Going to log first load --> referrer : ", document.referrer);
      // this can get me the document.referrer properly, if I come to the website from a third party source like google search.
      global.analytics.page(window.location.href,
        {referrer: document.referrer}
      )
    }
  }

  static async getInitialProps ({ Component, router, ctx }) {
    let pageProps = {}

    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx)
    }

    return { pageProps }
  }

  state = {
    history: [] // keep history items in state
  };

  componentDidUpdate() {

    const { history } = this.state;
    const { asPath } = this.props.router;





    // if current route (`asPath`) does not equal
    // the latest item in the history,
    // it is changed so lets save it
    if (history[history.length - 1] !== asPath) {

      
      global.analytics.page(window.location.href, {
        referrer: history[history.length - 1] ? history[history.length - 1] : ""
      })
      // this simulates the document.referrer on pages after the user navigates
      this.setState(prevState => ({ history: [...prevState.history, asPath] }));
    }
  }

Таким образом, с комбинацией history[history.length - 1] ? history[history.length - 1] : "" и const isBrowser = typeof window !== 'undefined'; я могу смоделировать document.referrer для всех случаев. Но я упускаю один случай, предположим, я в Google, целевая страница моего сайта - A, тогда A указывает на B

Тогда google to A --> я получаю document.referrer как google

Затем A to B --> я получаю document.referrer как A, что согласуется с поведением.

Но теперь, если я обновлю страницу B, мой document.referrer снова станет google.

Я думаю, что могу сохранить последний известный предыдущий URL-адрес в локальном хранилище, но это будет анти-шаблон, поскольку кнопка «Назад» в браузере может правильно перевести пользователя на предыдущую страницу (A), поэтому где-то данные уже есть. В настоящее время я могу жить с этим решением, так как я использую его только для целей аналитики на segment.com и аналитике Google, поэтому обновление немного испортит мои аналитические данные, но я все еще жду идеального решения, чтобы получить точные данные.

Я использовал Context для этого

В _app.tsx

import { HistoryProvider } from '../contexts/History'

const MyApp: React.FC<AppProps> = ({ Component, pageProps }) => {
  return (
    <ThemeProvider theme = {theme}>
      <Header />
        <HistoryProvider>
          <Component {...pageProps} />
        </HistoryProvider>...

/contexts/History.tsx

import { useRouter } from 'next/router'
import React, { createContext, useState, useEffect, useContext } from 'react'

interface HValidation {
  history: string[]
  setHistory(data: string[]): void
  back(): void
}

const HistoryContext = createContext<HValidation>({} as HValidation)
export const HistoryProvider: React.FC = ({ children }) => {
  const { asPath, push, pathname } = useRouter()
  const [history, setHistory] = useState<string[]>([])

  function back() {
    for (let i = history.length - 2; i >= 0; i--) {
      const route = history[i]
      if (!route.includes('#') && route !== pathname) {
        push(route)

        // if you want to pop history on back
        const newHistory = history.slice(0, i)
        setHistory(newHistory)

        break
      }
    }
  }

  useEffect(() => {
    setHistory(previous => [...previous, asPath])
  }, [asPath])

  return (
    <HistoryContext.Provider
      value = {{
        back,
        history,
        setHistory,
      }}
    >
      {children}
    </HistoryContext.Provider>
  )
}

export function useHistory(): HValidation {
  const context = useContext(HistoryContext)
  return context
}

В любой компонент вы можете использовать

import { useHistory } from '../../contexts/History'

const ContentHeader: React.FC<ContentHeaderProps> = ({ title, hideBack }) => {
    const { history, back } = useHistory() ...

Я использовал этот компонент для обратной истории, игнорируя ссылки с хэшем (#), потому что собственный маршрутизатор.назад() глючил, когда мне приходилось прокручивать страницу до некоторых идентификаторов страниц. Я хотел вернуться на последнюю страницу, а не на последний якорь

РЕДАКТИРОВАТЬ 04.01.2021

Вы также можете установить запасной маршрут для «назад».

back(fallbackRoute?: string): void

function back(fallbackRoute?: string) {
  for (let i = history.length - 2; i >= 0; i--) {
    const route = history[i]
    console.info({ route, pathname })
    if (!route.includes('#') && route !== pathname) {
      push(route)
      const newHistory = history.slice(0, i)
      setHistory(newHistory)
      return
    }
  }
  if (fallbackRoute) {
    router.push(fallbackRoute)
  }
}

Хотел бы я понять, как это должно работать.

Aaron Tomlinson 25.08.2021 08:12

Допустим, есть страница /profile, которая должна отображаться, если пользователь вошел в систему, иначе пользователь должен быть перенаправлен на /login, после входа пользователя на /login он должен быть перемещен на предыдущую страницу (здесь/profile), но не на другой веб-сайт или в новую вкладку.

  1. В /profile вот как вы должны перенаправить на /login

Router.push('/login?referer=profile', '/login')

  1. В /login после успешного входа пользователя используйте:

Router.push(Router.query.referer?.toString||'/')

Надеюсь, это помогло.

Недавно у меня была эта проблема, и я использовал следующее решение для возврата на предыдущую страницу.

В своем компоненте я использовал хук useRouter() из Next.js. Этот хук создает объект маршрутизатора, который имеет функцию back(). Эту функцию можно использовать для тега <a> для перенаправления обратно следующим образом.

const Component: React.FC = () => {
  const router = useRouter();

  return (
    <>
      <a onClick = {() => router.back()}>Go back to the last page</a>
    </>
  );
};

Обратите внимание, что эта функция нет создает URL-адрес, который вы можете использовать в качестве значения в href, что является неудачным. Но я думаю, что это решение простое, но эффективное.

Ссылка: https://nextjs.org/docs/api-reference/next/router#routerback

Другие вопросы по теме