我是 Next.js 的新手,我想知道如何从起始页( / )重定向到 / hello-nextjs 例如。用户加载页面后,确定路径是否=== / 重定向到 / hello-nextjs
在反应路由器中,我们执行以下操作:
<Switch>
<Route path="/hello-nextjs" exact component={HelloNextjs} />
<Redirect to="/hello-nextjs" /> // or <Route path="/" exact render={() => <Redirect to="/hello-nextjs" />} />
</Switch>
答案 0 :(得分:18)
嗨,这是在所有情况下都可以使用的示例组件:
Vulcan next starter withPrivate access
答案是巨大的,很抱歉,如果我以某种方式违反了SO规则,但是我不想粘贴180行代码。如果要同时支持SSR和静态导出,则在Next中没有简单的模式可以处理重定向。
以下每种情况都需要特定的模式:
在撰写本文时(下一个9.4),您必须使用getInitialProps
而不是getServerSideProps
,否则您将失去执行next export
的能力。
如@Arthur在评论中所述,9.5还包括设置redirects in next.config.js的可能性。 我尚不清楚此功能的局限性,但似乎是全局重定向,例如当您需要移动页面或仅在有限的时间内允许访问时。 因此,它们并不是要处理例如身份验证,因为它们似乎无法访问请求上下文。再次确认。
with-cookie-auth
示例在getInitialProps
中重定向。我不确定这是否是一种有效的模式,但这是代码:
Profile.getInitialProps = async ctx => {
const { token } = nextCookie(ctx)
const apiUrl = getHost(ctx.req) + '/api/profile'
const redirectOnError = () =>
typeof window !== 'undefined'
? Router.push('/login')
: ctx.res.writeHead(302, { Location: '/login' }).end()
try {
const response = await fetch(apiUrl, {
credentials: 'include',
headers: {
Authorization: JSON.stringify({ token }),
},
})
if (response.ok) {
const js = await response.json()
console.log('js', js)
return js
} else {
// https://github.com/developit/unfetch#caveats
return await redirectOnError()
}
} catch (error) {
// Implementation or Network error
return redirectOnError()
}
}
它同时处理服务器端和客户端。 fetch
调用实际上是获得auth令牌的调用,您可能希望将其封装到一个单独的函数中。
这是最常见的情况。您现在需要重定向以避免第一次加载时初始页面闪烁。
MyApp.getInitialProps = async appContext => {
const currentUser = await getCurrentUser(); // define this beforehand
const appProps = await App.getInitialProps(appContext);
// check that we are in SSR mode (NOT static and NOT client-side)
if (typeof window === "undefined" && appContext.ctx.res.writeHead) {
if (!currentUser && !isPublicRoute(appContext.router.pathname)) {
appContext.ctx.res.writeHead(302, { Location: "/account/login" });
appContext.ctx.res.end();
}
}
return { ...appProps, currentUser };
};
2.在componentDidMount中重定向(在禁用SSR(例如在静态模式下)时很有用)
这是客户端渲染的后备。
componentDidMount() {
const { currentUser, router } = this.props;
if (!currentUser && !isPublicRoute(router.pathname)) {
Router.push("/account/login");
}
}
我无法避免在静态模式下刷新初始页面,请添加这一点,因为您无法在静态构建过程中进行重定向,但它似乎比通常的方法要好。我会在取得进展时尝试进行编辑。
Relevant issue, which sadly ends up with a client only answer
答案 1 :(得分:8)
有三种方法。
1。重定向事件或功能
import Router from 'next/router';
<button type="button" onClick={() => Router.push('/myroute')} />
2。使用挂钩重定向:
import Router , {useRouter} from 'next/router';
const router = useRouter()
<button type="button" onClick={() => router.push('/myroute')} />
3。使用链接重定向:
基于Nextjs文档的链接中,<a>
标签是必需的!
import Link from 'next/link';
<Link href="/myroute">
<a>myroute</a>
</Link>
服务器端路由还有其他一些选项,asPath
。在所有描述的方法中,您都可以添加asPath来重定向客户端和服务器端。
答案 2 :(得分:4)
@Nico的答案解决了使用类时的问题。
如果使用函数,则不能使用componentDidMount
。相反,您可以使用React Hooks useEffect
。
import React, {useEffect} from 'react';
export default function App() {
const classes = useStyles();
useEffect(() => {
const {pathname} = Router
if(pathname == '/' ){
Router.push('/templates/mainpage1')
}
}
, []);
return (
null
)
}
在2019年,React introduced挂钩。比类更快,更有效。
答案 3 :(得分:4)
这里有2个复制粘贴级别的示例:一个用于浏览器,一个用于服务器。
https://dev.to/justincy/client-side-and-server-side-redirection-in-next-js-3ile
假设您要从根(/)重定向到名为home:(/ home)的页面
在主索引文件中,粘贴以下内容:
客户端
import { useRouter } from 'next/router'
function RedirectPage() {
const router = useRouter()
// Make sure we're in the browser
if (typeof window !== 'undefined') {
router.push('/home')
}
}
export default RedirectPage
服务器端
import { useRouter } from 'next/router'
function RedirectPage({ ctx }) {
const router = useRouter()
// Make sure we're in the browser
if (typeof window !== 'undefined') {
router.push('/home');
return;
}
}
RedirectPage.getInitialProps = ctx => {
// We check for ctx.res to make sure we're on the server.
if (ctx.res) {
ctx.res.writeHead(302, { Location: '/home' });
ctx.res.end();
}
return { };
}
export default RedirectPage
答案 4 :(得分:3)
我已经在我的Next.JS
应用中实现了此功能,方法是定义一个用于重定向服务器端和客户端的根页面。这是根页面的代码:
import { useEffect } from "react";
import Router from "next/router";
const redirectTo = "/hello-nextjs";
const RootPage = () => {
useEffect(() => Router.push(redirectTo));
return null;
};
RootPage.getInitialProps = (ctx) => {
if (ctx.req) {
ctx.res.writeHead(302, { Location: redirectTo });
ctx.res.end();
}
};
export default RootPage;
答案 5 :(得分:2)
对NextJS 9.5.0+
有效
next.config.js
文件module.exports = {
async redirects() {
return [
{
source: '/team',
destination: '/about',
permanent: false,
},
{
source: "/blog",
destination:
"https://blog.dundermifflin.com",
permanent: true,
},
];
},
};
https://github.com/vercel/next.js/tree/canary/examples/redirects
答案 6 :(得分:2)
Next.js 10+ 为我们提供了一些额外的优雅解决方案来进行重定向。
SERVER-SIDE - 你应该使用 getServerSideProps
下面的例子假设我们有一些额外的会话要检查(但可以
任何你想要的)。如果会话为空并且我们在服务器端
(context.res
),这意味着用户没有登录,我们应该
重定向到登录页面 (/login
).. 另一种方式我们可以通过 session
到 props
并重定向到 /dashboard
:
export const getServerSideProps = async (context) => {
const session = await getSession(context);
if(context.res && !session) {
return {
redirect: {
permanent: false,
destination: '/login'
}
}
}
return {
props: { session },
redirect: {
permanent: false,
destination: '/dashboard'
}
}
}
CLIENT-SIDE - 例如,您可以使用 useRouter
钩子:
const router = useRouter();
const [ session, loading ] = useSession();
if (typeof window !== 'undefined' && loading) return null;
if (typeof window !== 'undefined' && !session) {
router.push('/login');
}
router.push('/dashboard');
答案 7 :(得分:2)
在 NextJs v9.5 及更高版本中,您可以在 next.config.js 文件中配置重定向和重写。
但如果您使用 trailingSlash: true
,请确保源路径以斜杠结尾,以便正确匹配。
module.exports = {
trailingSlash: true,
async redirects() {
return [
{
source: '/old/:slug/', // Notice the slash at the end
destination: '/new/:slug',
permanent: false,
},
]
},
}
您还需要考虑可能影响路由的其他插件和配置,例如 next-images。
文档:https://nextjs.org/docs/api-reference/next.config.js/redirects
答案 8 :(得分:1)
在next.js
中,您可以使用Router
进行重定向:
import Router from 'next/router'
componentDidMount(){
const {pathname} = Router
if(pathname == '/' ){
Router.push('/hello-nextjs')
}
}
答案 9 :(得分:1)
如果您要确保您的应用程序像SPA一样运行并且想要拦截用户粘贴到地址栏中的传入的无效(或有效)路径名,那么这是一种快速/简便的方法。 / p>
假设您的路径是
enum ERoutes {
HOME = '/',
ABOUT = '/about',
CONTACT = '/contact'
}
添加自定义_error
页面(如果您还没有页面的话),并将其添加到其中:
import React from 'react';
import { NextPage } from 'next';
import { useDispatch } from 'react-redux';
import { useRouter } from 'next/router';
const Error: NextPage = () => {
const { asPath, push } = useRouter();
const dispatch = useDispatch();
React.useEffect(() => {
const routeValid = Object.values(ERoutes).includes(asPath);
if (routeValid) {
// do some stuff, such as assigning redux state to then render SPA content in your index page
} else {
// you can either continue to render this _error component, or redirect to your index page,
// where you may have your own error component that is displayed based on your app state.
// In my case, I always redirect to '/' (as you can see below, where I push('/'), but before doing so,
// I dispatch relevant redux actions based on the situation
}
// I redirect to root always, but you can redirect only if routeValid === true
push('/');
}, []);
return (
<div>Error because '{asPath}' does not exist</div>
);
};
export default Error;
答案 10 :(得分:-1)
redirect-to.ts
import Router from "next/router";
export default function redirectTo(
destination: any,
{ res, status }: any = {}
): void {
if (res) {
res.writeHead(status || 302, { Location: destination });
res.end();
} else if (destination[0] === "/" && destination[1] !== "/") {
Router.push(destination);
} else {
window.location = destination;
}
}
_app.tsx
import App, {AppContext} from 'next/app'
import Router from "next/router"
import React from 'react'
import redirectTo from "../utils/redirect-to"
export default class MyApp extends App {
public static async getInitialProps({Component, ctx}: AppContext): Promise<{pageProps: {}}> {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
if (ctx.pathname === "" || ctx.pathname === "/_error") {
redirectTo("/hello-next-js", { res: ctx.res, status: 301 }); <== Redirect-To
return {pageProps};
}
return {pageProps};
}
render() {
const {Component, pageProps} = this.props;
return <Component {...pageProps}/>
}
}