如何在 nextjs 中获取上一个 url

How to get previous url in nextjs

如何在nextjs中获取之前的URL? 我认为值 this.props.router.asPathnextProps.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.log(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.log(this.props.router.asPath) // /about
    console.log(nextProps.router.asPath) // /about
    console.log('window.history.previous.href', window.history.previous) // undefined
  }
}

我该如何解决?或者如何让之前的URL登录后移动页面?

我认为您可以在全局状态中实现自定义历史记录

像这样

_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]);
}

希望对您有所帮助!

您在 getServerSideProps 或任何其他数据获取方法

的上下文中找到了 Referer(所以之前的 URL )

作为

    context.req.headers.referer  

代码示例

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

我尝试做类似于 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.log("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() ...

我已经使用这个组件来支持忽略带有哈希 (#) 的链接的历史记录,因为当我必须滚动页面时,本机 router.back() 出现错误一些页面ID 我想回到最后一页,而不是最后一个锚

编辑 2021 年 1 月 4 日

您还可以为“返回”设置后备路线。

back(fallbackRoute?: string): void

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

假设有一个 /profile 页面,如果用户已登录则应该呈现该页面,否则用户应该被重定向到 /login,在用户登录 /login 后,它应该是推送到上一页(此处/profile)但不在其他网站或新标签页上。

  1. /profile 中,这就是重定向到 /login
  2. 的方式

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

  1. /login用户登录成功后,使用:

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

希望对您有所帮助。

我最近遇到了这个问题,并使用以下解决方案路由回上一页。

在我的组件中,我使用了 Next.js 中的 useRouter() 钩子。该钩子生成一个具有 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

更简单的方法是

import { useRouter } from 'next/router';

const router = useRouter();

router.back()

我无法获得以前的 url 但使用下面的代码我可以找到后面 URL 或没有:

typeof window !== 'undefined' && +window?.history?.state?.idx > 0

    const back = async () => {
      if (typeof window !== 'undefined' && +window?.history?.state?.idx > 0) {
        await Router.back()
      } else {
        await Router.replace(fallbackURL)
      }
    }

我一直在寻找一种非常简单的方法来做到这一点,因为这里的一些答案对于实现这么简单的事情来说似乎有点复杂。 router.back() 在这种情况下似乎效果不佳,因为在我的情况下,它有时会一直返回并离开我的网站。 所以,我想,还有什么比 localStorage 更好的方法呢?

当我需要将用户发送到 '/login' 路由时,我将当前路由添加到 localStorage

  if (!auth.user) {
  window.localStorage.setItem("path", router.asPath);
  router.replace("/login");
  return <div> redirecting to login... </div>;
}

一旦用户sign-in,我将他们送回上一页(其路由已保存在localStorage

if (auth.user) {
  router.replace(localStorage.getItem("path") || "/");
  return <div> Loading... </div>
  );
}

你可以边测试边观察localStorage看看是怎么回事。 我希望这对某人有帮助