Next.js: Docs: Missing information about redirecting

Created on 10 Apr 2020  路  11Comments  路  Source: vercel/next.js

Feature request

Is your feature request related to a problem? Please describe.

I've been looking through the docs and I can't seem to find any information on how to redirect. There used to be a wiki page but that got deleted, and so the only information I could find are in GitHub issues.

  1. So it seems okay to redirect in getInitialProps, however that is being deprecated in favor of getServerSideProps. Is it safe to redirect in there?
  2. However, @Timer said that you shouldn't redirect in getInitialProps using the client-side router (here). Which makes the method that was mentioned in the original wiki page incorrect.

So what is the best way to redirect in the current version of next? Looking at zeit.co it looks like its being done in getInitialProps but I can't be sure. If I had to venture a guess you should do it in getServerSideProps and useEffect in the function for client-side redirection.

Describe the solution you'd like

A page that describes the recommended way to redirect on the server-side and/or client side.

Describe alternatives you've considered

N/A

Additional context

N/A

Most helpful comment

Opened a RFC for redirecting here: #14890

All 11 comments

Bump

+1 for this

So it seems okay to redirect in getInitialProps, however that is being deprecated in favor of getServerSideProps

@nahtnam I don't believe that's exactly true.. From the Next.js Blog:

These improvements are API additions. All new functionality is completely backwards compatible and can be incrementally adopted. No deprecations are introduced and getInitialProps will continue to function as it currently does. We do encourage adopting these new methods on new pages and projects.

Anyways... +1.. Next.js should have a recommended (or even standard) way to do redirects.

Based on @Timer's enlightening comment (https://github.com/zeit/next.js/issues/4931#issuecomment-512787861), I derived a nice clean abstraction that I want to share.

Define the Redirect component like this:

// lib/redirect.js
import { useRouter } from 'next/router'
import { useEffect } from 'react'

export function Redirect ({ to, action = 'push' }) {
  const router = useRouter()
  useEffect(() => {
    router[action](to)
  })
  return null
}

Use the Redirect component like this:

// pages/some-page.js
import { Redirect } from '../lib/redirect'

export default function SomePage {
  if (someCondition) {
    return <Redirect to="/some-other-page" />
  }
  return <p>Normal content...</p>
}

Note: It can be used deep within the component tree.

At first I was doing something more complex and less flexible, but I eventually realized that there's no need to mess with getInitialProps or getServerSideProps to handle redirects.

The only downside is (as with @Timer's example) we momentarily show the user a blank page. That could be replaced with a "Redirecting..." message but I don't think that is much nicer.

Happy to make a PR to add this to the documentation if maintainers deem this an acceptable way to do redirects.

I don't think this is proper though, if we have the ability to SSR, we shouldn't be showing a blank screen right? That would kill SEO

@zenflow Yeah, client-side redirects are nice and all, but ideally we'd have the server do an HTTP 301 redirect if it's the entry point, and the client either doing a client-side redirect on navigation, or even simply rewriting all links to the destination URL.

If I had to venture a guess, this is what the new redirect should be something like this, but is this the correct way to do it?

export default function Post() {
  useEffect(() => {
    Router.push('/signin')
  })
}

export async function getServerSideProps({ res }}) {
  res.writeHead(status || 302, { Location: '/signup' });
  res.end();
}

If I had to venture a guess, this is what the new redirect should be something like this, but is this the correct way to do it?

export default function Post() {
  useEffect(() => {
  Router.push('/signin')
  })
}

export async function getServerSideProps({ res }}) {
  res.writeHead(status || 302, { Location: '/signup' });
  res.end();
}

I have tried that. It works fine sometimes. But in catch case, it not working well. Do you try it? I don't think it is the right way right now.

export default function Post() {
  useEffect(() => {
    Router.push('/signin')
  })
 return <div>something</div>
}

export async function getServerSideProps({ res }}) {
  try {
    const data = await fetchSomeData();
    return {props: { data }};
  } catch (err) {
    res.writeHead(status || 302, { Location: '/signup' });
    res.end();
    return {props: { }};
  }
}

Yeah, client-side redirects are nice and all, but ideally we'd have the server do an HTTP 301 redirect if it's the entry point, and the client either doing a client-side redirect on navigation, or even simply rewriting all links to the destination URL.

@Vinnl Yup, I agree that's the ideal. But since it's not clear how the ideal (client or server redirects as needed) can be possible...

For situations where we don't need SSR (e.g. redirect after login, redirect away from protected pages) we can use <Redirect>, which is just an abstraction on the suggested method of redirecting.

It's possible to render some "Redirecting..." screen instead of a blank page if you wish.

I think it's a good solution for when client-side redirects work for you.

That said, I'm still hoping we can have a unified way of doing redirects, which works seamlessly on both server & browser. (Technically a different issue from this one about documentation)

Opened a RFC for redirecting here: #14890

Was this page helpful?
0 / 5 - 0 ratings

Related issues

timneutkens picture timneutkens  路  250Comments

ematipico picture ematipico  路  66Comments

robinvdvleuten picture robinvdvleuten  路  74Comments

iamstarkov picture iamstarkov  路  119Comments

nickredmark picture nickredmark  路  60Comments