1

I have page which can have one of 2 params. email and hash if there are not present I want to redirect the user.

/confirm-email?email=user@email.com

I have tried the following:

const router = useRouter();
const { email, hash } = router.query;

useEffect(() => {
  if (!email && !hash) {
    router.push('/');
  } else if (hash) {
    // Do stuff
  }
}, [email, hash, router]);

But the problem on first render both of them are undefined and the user gets redirected even if the hash or email params are present.

How can I fix this ? any suggestions ?

Xaarth
  • 1,021
  • 3
  • 12
  • 34
  • try to use something like useRef and keep value there so at 1st render you will not check anything, and after that check again. so basically onUpdate kind of hook. if further help need i can write down in the answer section. – SebMaz93 May 27 '21 at 18:38
  • We don’t need to use refs even I think – Xaarth May 27 '21 at 21:10

3 Answers3

3

After doing some research. I have figured out it's best check if the params exists or not inside getServerSideProps()

export async function getServerSideProps({ query }) {
  if (!query.email && !query.hash) {
    return {
      notFound: true,
    };
  }

  return {
    props: {},
  };
}
Xaarth
  • 1,021
  • 3
  • 12
  • 34
0
import { useRouter } from 'next/router'
import { useEffect } from 'react';

const MyComponentCheck = () => {
    const router = useRouter();


    useEffect(() => {
        if (typeof window) {
            const a = window.location.href;
            if (a?.includes('your_query_param')) {

            } else {
                router.push('/')
            }
        }
    }, [])
}

export default MyComponentCheck;

You can check for the window object, that way your code will only runs when you have the URL preventing the undefined issue

-2
if (hash)

looks unecessary.

and

query: Object - The query string parsed to an object. It will be an empty object during prerendering if the page doesn't have data fetching requirements. Defaults to {}

is a quote from https://nextjs.org/docs/api-reference/next/router

I assume that is the location of the problem.

the param would be the file name in Router.query

for example:

import { useRouter } from 'next/router'

const Post = () => {
  const router = useRouter()
  const { pid } = router.query

  return <p>Post: {pid}</p>
}

export default Post

for the file [pid].js in pages/morepages/[pid].js

Or maybe, to use 2 param options you need to go to a website page that uses both. So there has to be a hashtag between them.

Such as "website/emial/hash"

Alexander Hemming
  • 753
  • 1
  • 6
  • 28
  • the route parameters will override query parameters with the same name. Can you share your file name so we can see if that is where the problem is? – Alexander Hemming May 27 '21 at 18:59
  • That is the problem I highlighted. You need to use square brackets. Then you use the route.query to refer to the "key" which is the name in the file in the square brackets, not the value that is in the url. – Alexander Hemming May 27 '21 at 19:01
  • As in, because you are not using dynamic routing atall the route.query is pointing to nothing. – Alexander Hemming May 27 '21 at 19:03
  • If i do `confirm-email/[somename].js` how do I know if the param is an email or hash. I have to create 2 files then. right ? – Xaarth May 27 '21 at 19:03
  • you can do this to make it easier to get the params out: /[email]/[hash].js But the docs highlight how you can go about the normal way, after you have originally used the dynamic routing method, of having something in square brackets so that it can be looked at in router.query – Alexander Hemming May 27 '21 at 19:05
  • 1
    only email or hash will be available. both will not appear at the same time. by using `/[email]/[hash].js` to provide hash I will have to do `/user@email.com/hash` right? – Xaarth May 27 '21 at 19:06
  • https://nextjs.org/docs/routing/dynamic-routes in this is shows very clearly that both will appear in the methods I have state. But if you do not use the square brackets in the file/folder names, then there will be nothing you can get from router.query – Alexander Hemming May 27 '21 at 19:08
  • yes, for that method that would be the correct action. but you can also use your original style if you use the square brackets on only the file name. – Alexander Hemming May 27 '21 at 19:09
  • Similarly, the route /post/abc?foo=bar will have the following query object: { "foo": "bar", "pid": "abc" } (from that website) – Alexander Hemming May 27 '21 at 19:11
  • I honestly didn't understand your solution at all. I guess will do some more research try some things and maybe than I understand it – Xaarth May 27 '21 at 19:13