【问题标题】:How to get previous url in nextjs如何在 nextjs 中获取上一个 url
【发布时间】:2019-08-29 03:25:26
【问题描述】:

如何在 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来移动页面?

【问题讨论】:

标签: next.js


【解决方案1】:

您可以在 getServerSideProps 或任何其他数据获取方法的上下文中找到引用者(即之前的 URL)

作为

    context.req.headers.referer  

代码示例

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

【讨论】:

  • 为了节省一些往返时间 - 它确实是“推荐人”,中间有一个 r,而不是两个
  • 略有不同但与此答案相关我需要在 Next.JS API 预览路由中获取引用者以在退出预览路由被击中时重定向回原始引用者,您可以通过以下方式执行此操作使用request.headers.referer,其中request 输入为NextApiRequest
【解决方案2】:

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

类似的东西

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

希望这会有所帮助!

【讨论】:

    【解决方案3】:

    我已经使用了 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() ...
    

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

    编辑 01/04/2021

    你还可以为“back”设置一个后备路由。

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

    【讨论】:

    • 我希望我能理解这应该如何工作。
    【解决方案4】:

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

    1. /profile 这就是你应该如何重定向到/login

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

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

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

    希望这会有所帮助。

    【讨论】:

      【解决方案5】:

      我尝试做类似于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。但我错过了一个案例,假设我在谷歌,我的网站登陆页面是 A,然后 A 指向 B

      然后google to A --> 我得到document.referrergoogle

      然后A to B --> 我得到document.referrerA 这与行为一致。

      但是现在如果我刷新页面 B,那么我的document.referrer 又变成了google

      我想我可以将最后一个已知的上一个 URL 保存在本地存储中,但这将是一种反模式,因为浏览器的后退按钮可以正确地将用户带到上一页 (A),所以数据在某处已经有了。目前我可以接受这个解决方案,因为我只在 segment.com 和谷歌分析上将它用于分析目的,所以刷新会稍微弄乱我的分析数据,但仍然期待一个完美的解决方案,以便获得准确的数据。

      【讨论】:

        【解决方案6】:

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

        在我的组件中,我使用了 Next.js 中的 useRouter() 挂钩。这个钩子产生一个具有back() 函数的路由器对象。这个函数可以用在&lt;a&gt;标签上,通过以下方式重定向回来。

        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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-07-25
          • 2014-09-26
          • 2011-04-01
          • 2021-08-12
          • 1970-01-01
          • 2022-11-11
          • 1970-01-01
          相关资源
          最近更新 更多