0

I am using a dynamic router in Next.js, and this is the code

import { useRouter } from "next/router";

const exampleFunction = () => {

  const router = useRouter();
  const {slug}  = router.query;
  console.log(slug);

  return (
    <h1>{slug}</h1>
  );
};

export default exampleFunction;

The location of the file is:

lms/client/pages/teacher/course/test/[slug].js

When I access the link like this:

http://localhost:3000/teacher/course/test/testmw

I can see the slug is being rendered in the browser; however when I look at the console, I see undefined value before the actual value of the slug.

I wonder this is something I've done wrong or this is the expected behavior of Next.js?

I've been suggested a similar question. However, the answer is mostly about getting the route in server-side, I wonder if I can effectively do the same thing on the client-side.

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
Dory Nguyen
  • 361
  • 2
  • 14
  • what does `console.log(router)` say? – Nikita Mazur Jul 06 '21 at 00:31
  • this is a common behavior of React apps The component mounted before the router query has been resolved. If you wanna get initially your ```slug``` exactly before the component mounted (server-sided) . You can use one of these API nextjs provided, [getStaticProps](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation), [getStaticPaths](https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation) or [getServerSideProps](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering) – Raden Kriting Jul 06 '21 at 03:58
  • @NikitaMazur it's a next object but query is empty `{pathname: "/instructor/course/test/[slug]", route: "/instructor/course/test/[slug]", query: {…}, asPath: "/instructor/course/test/[slug]", components: {…}, …}` – Dory Nguyen Jul 06 '21 at 07:57
  • @RadenKriting Yes, I'm still work on the best way to get the router query. at the moment I have write a hook `useEffect` with the dependency `[slug]` to fetch data, which I doubt is a good way because it unnecessarily sends request to server more than once. – Dory Nguyen Jul 06 '21 at 07:59
  • Does this answer your question? [nextJS SSR useRouter() does not work when refresh page](https://stackoverflow.com/questions/63691329/nextjs-ssr-userouter-does-not-work-when-refresh-page) – juliomalves Jul 06 '21 at 08:15
  • @juliomalves yes, it practically does, but preferably I would rather do it on the client side, which is primarily the reason why I work with next.js – Dory Nguyen Jul 06 '21 at 08:39

2 Answers2

3

"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 {}"

Initially, "query" object will be {} so "slug" will be undefined. This is what you should do :

return (
   {slug &&  <h1>slug</h1>}
  );

If "slug" is not defined, do not render element.

To solve this problem, you need to get the "slug" on the server with "getServerSideProps" and pass it to the component:

export const getServerSideProps = async (context) => {
  const { slug } = context.query;
  // If slug is "undefined", since "undefined" cannot be serialized, server will throw error
  // But null can be serializable
  if (!slug) {
    slug = null;
  }
  // now we are passing the slug to the component
  return { props: { slug:slug } };
};

Now your component has props.slug.

const exampleFunction = (props) => {
const {slug}=props // you could just pass {slug} to the component

  return (
     {slug &&  <h1>slug</h1>}
  );
};

export default exampleFunction;
Yilmaz
  • 35,338
  • 10
  • 157
  • 202
0

It first shows undefined because it is impossible to get query from route at first render. I assume you will get the actual value of slug after second render. You are doing alright , it is next.js behavior. You can look at getStaticpaths or you can useEffect to check if query is loaded or not and perform your task as needed

Saral Karki
  • 4,530
  • 2
  • 7
  • 10