Exploring NextJS Features
Tags: javascript
Published: 2020-07-27 19:42:49

If you read and followed the instructions in the previous post in this series, then you created a NextJS web app, though you might have already created a NextJS app before this, some other way. In this post I'm going to compare the method of writing a Next app with writing a React app.

## Semantic differences between Next and React

The first thing you should know is that if you make a folder called `/pages` in your project, NextJS handles the routing for you for components in that folder, by looking at the file name of your component and naming the path accordingly. So, a file called `/pages/profile.ts` in your project will be accessible at the `/profile` path.

You can also have changing names for the paths, using a technique called *dynamic routing*. Dynamic routing in NextJS is when you create a file called `/pages/posts/[someID].ts`, you can access paths such as `/posts/123` and `/posts/abc`. Whatever name `someID` you put will be accessible from `useRouter().query`, and useRouter comes from a NextJS package.

This is how you use `useRouter` in practice:

```js
// file: /pages/posts/[someID].js
import { useRouter } from 'next/router'

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

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

export default Post
```

Now that you programmatically retrieved the value of the ID, you can conditionally render the appropriate content using it.

Also, you can pass query parameters of the form `/somepath/replaced-id?key=value` into NextJS apps using dynamic routing, you use the same `query` method that was used in the sample, but it will be an object that looks something like `{ "foo": "bar", "pid": "abc" }`.

This is also what happens if you substitute an ID in a route below another route that is also a substituted ID, such as `/pages/post/[pid]/[comment].js` --> `/post/abc/a-comment`, and its query object will be:

```js
{ "pid": "abc", "comment": "a-comment" }
```

There is even a mechanism to capture all the child paths of a route using a single file name. Using the blog post example again, if I make a file in my project called `/pages/post/[...someID].js`, it will handle all routes from `/posts/a`, `/posts/foobar`, `/posts/foobar/baz` and others. By doing this, you have to render the appropriate page for each path.

Since static routes have a higher priority than dynamic routes, this is an excellent way to implement 404 pages; Just put a file called `/pages/[notFound].js` or any other name instead of notFound.

And then there is *data fetching*. This handy feature allows you retrieve state from a server before rendering the page. In plain React there is no intuitive way that I know of to make a request and collect the data before the page renders, so the fact that NextJS made it this easy to get state gives it a major advantage.

It can only get data though, not send data to a server.

When a component is built, NextJS immediately calls the exported function `getStaticProps()` defined in the component. Use it to fetch your props from a server, and then return an object containing a `props` key that has all your props inside. Here is an example of a typical getStaticProps function:

```js
// Blog component omitted...

// This function gets called at build time
// It's defined at the top level of a file, assuming you are using React hooks.
export async function getStaticProps() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // By returning { props: posts }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts,
    },
  }
}
```

There is also a function that fetches the ID, the one inside `[...someID]`, of the page to render called `getStaticPaths`, and it's defined similarly to getStaticProps.

```js
// This function gets called at build time
export async function getStaticPaths() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => `/posts/${post.id}`)

  // We'll pre-render only these paths at build time.
  // { fallback: false } means other routes should 404.
  return { paths, fallback: false }
}
```

Basically what happens if you don't use this is that for each `/post/1`, `/post/2` and such, it will render the same page on all of them which might not be what you desire.

In the above example, there is a `fallback` parameter which can be true or false, When it's false, paths not returned by getStaticPaths make a 404 error. When it's true, then those paths don't 404, instead a special flag is set that loads a fallback version of the page with no props defined. This enables you to render a fallback version of a page.

In the below snippet, a fallback page is displayed while getStaticProps is being run, until it finishes running, then props will be defined and the normal page is rendered. This requires that getStaticPaths returns `fallback: true`.

```js
function Post({ post }) {
  const router = useRouter()

  // If the page is not yet generated, this will be displayed
  // initially until getStaticProps() finishes running
  if (router.isFallback) {
    return <div>Loading...</div>
  }

  // Render post...
}
```

## That's all folks

We reached the end of the NextJS overview. If you see any errors, please let me know so I can correct them.