Как я могу получить предыдущий 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-адрес для перемещения страницы после входа в систему?
Я думаю, вы можете реализовать пользовательскую историю в глобальном состоянии.
Что-то вроде этого
_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 посередине, а не с двумя
Немного отличается, но связан с этим ответом. Мне нужно было, чтобы реферер в маршруте предварительного просмотра API Next.JS перенаправлял обратно к исходному рефереру при попадании на маршрут предварительного просмотра выхода, вы можете сделать это, используя request.headers.referer
, где request
вводится в NextApiRequest
Я пытался сделать что-то похожее на ответ 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)
}
}
Хотел бы я понять, как это должно работать.
Допустим, есть страница /profile
, которая должна отображаться, если пользователь вошел в систему, иначе пользователь должен быть перенаправлен на /login
, после входа пользователя на /login
он должен быть перемещен на предыдущую страницу (здесь/profile
), но не на другой веб-сайт или в новую вкладку.
/profile
вот как вы должны перенаправить на /login
Router.push('/login?referer=profile', '/login')
/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
Этот вопрос в основном дублирует: stackoverflow.com/a/65614253/10367188