如何在 nextjs 中获取上一个 url
How to get previous url in nextjs
如何在nextjs中获取之前的URL?
我认为值 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.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
)但不在其他网站或新标签页上。
- 在
/profile
中,这就是重定向到 /login
的方式
Router.push('/login?referer=profile', '/login')
- 在
/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看看是怎么回事。
我希望这对某人有帮助
如何在nextjs中获取之前的URL?
我认为值 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.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
)但不在其他网站或新标签页上。
- 在
/profile
中,这就是重定向到/login
的方式
Router.push('/login?referer=profile', '/login')
- 在
/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看看是怎么回事。 我希望这对某人有帮助