Question

How to get previous URL in Next.js?

How can I get the previous URL in Next.js? I thought the values this.props.router.asPath and nextProps.router.asPath are different.

Actually, I want to call router.push after login. I know that router.back goes to the previous page. But it's possible to go to another site. The users having history stacks go to the previous page, the users not having history stacks go to / main page.

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

How can I fix it? Or how can I get the previous URL to move page after login?

 48  108960  48
1 Jan 1970

Solution

 44

You find the Referer ( so the previous URL ) in the context of getServerSideProps or any other Data fetching methods

as

context.req.headers.referer  

example in code

export async function getServerSideProps(context) {
  console.log(context.req.headers.referer)
}
2020-08-03

Solution

 17

I've used Context do to this

In _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
}

In any component, you can use

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

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

I've used this component to back history ignoring links with hash (#), because the native router.back() was bugging when i have <a href="#someid" /> to scroll page to some page ids I wanted to go back to last page, and not the last anchor

EDIT 01/04/2021

You can also set a fallback route for "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)
  }
}
2020-12-15