Next.js. Create fast, search engine optimized React apps with zero configuration. A traditional React app is rendered client-side, where the browser starts with a shell of an HTML page lacking any rendered content.
From there, the browser fetches the JavaScript file containing the React code to render content to the page and make it interactive. But there are two major drawbacks with client-side rendering. One, the content is not reliably indexed by all search engines or read by social media linkbots.
And two, It can take longer to reach the first contentful paint when a user first lands on the web page. Next is a framework that allows you to build a React app, but render the content in advance on the server, so the first thing a user or search bot sees is the fully rendered HTML. After receiving this initial page, client-side rendering takes over and it works just like a traditional React app.
It's the best of both worlds. Fully rendered content for bots, highly interactive content for users. Inside of a Next project, you have a pages directory. Each JavaScript file defined here exports a React component that represents a route in the application. In other words, the file structure here mirrors the actual URLs that the user will navigate to.
And Next provides its own router to make navigation seamless. But the real magic comes into play when we talk about data fetching. Because Next can perform multiple server rendering strategies from a single project.
Static generation, or pre-rendering, allows you to render your pages at build time. Each page or component can implement a function called getStaticProps. It might fetch data from a cloud database, then pass the data as props to the component. You can then build your app to render out all the HTML locally and upload it to a storage bucket where it can be easily cached by a CDN. That works great for a blog or any kind of app where the data doesn't change often.
But if the data does change often, you can implement server-side rendering, which builds the HTML page each time it's requested by the user. In the component, we implement data fetching with the getServerSideProps function. Instead of running at build time, this function runs at request time.
That means the page will fetch the latest data on the server each time a new request comes in. That's great for pages with rapidly changing data, but maybe you want something in between. Yet another option is incremental static regeneration.
By simply adding a revalidate option to get static props, Next can regenerate a page whenever a new request comes in within a certain time interval. This has been Next.js in 100 seconds. If you want to see more short videos like this, make sure to subscribe and hit the like button. Then open up VS Code and get ready to go beyond 100 seconds with a full breakdown of Next. Before we get going, I'd like to point out that I'm working on a full React Next Firebase course, which I hope to have finally finished by the end of January, which will be available to Fireship Pro members.
My goal over the next few minutes is to teach you the fundamentals of Next while also explaining the complexities of server-side rendering. To follow along, open up the terminal and run npx create-next-app followed by the name of your app. And if you get lost at any point, make sure to grab the source code on GitHub or Fireship.io. Let's open up the project in VS Code and then go into the package.json file. In development, the only script we need to worry about is dev, which you can execute by running npm run dev from the command line, which will run our app on localhost 3000. That should give you the default boilerplate in the browser.
Now before we get into the React code, there's a few things that I want to point out. First, in the styles directory here, you'll notice how next supports CSS modules. In the globals file, you can define styles that apply to the entire application. But in other files with.module, you can define classes that only apply to a specific route or component. And you don't have to worry about coming up with a bunch of unique class names or naming conventions when managing your styles.
If you want to use styles from a certain module, You just import the stylesheet in your JavaScript, then reference your styles in JSX as if the styles were a JavaScript object. That's pretty awesome, but from there, let's shift our attention over to the pages directory. Inside this directory, we define all of the pages and routes for the application. At the highest level, we have this underscore app.js file, which is like the main entry point into the app.
In other words, every individual page will start from this template. Currently, the application only has one page, which points to the root URL, and is defined by the component in the index.js file. When a user navigates to this URL, next we'll find the default export, which is a React component, in this file.
So every file or page in your application needs to have one default export. To demonstrate this further, let's create our first route. In the pages directory, create a new file called hello.js.
Then we can define the content of this page by exporting a default React component from it. From there, we can go back to the browser. and navigate to localhost 3000 slash hello, and we should get the content of that component.
Congratulations, you just built your first web page with Next. But now let's imagine a route that's a little more complex. We have a cars route that should show a list of cars, then an infinite number of cars that might be dynamically generated under that URL.
We can implement a dynamic route like that by first creating a cars directory. Then inside the directory, we'll add an index.js file, which will show the main list of cars. Then for each individual car, we'll add a component that has a file name of brackets param name.js. The brackets make this route dynamic, which means anytime a user navigates to cars slash whatever, or cars slash Tesla, it will render the component in this file. To see that in action, let's go ahead and implement the component logic.
In the index file, we'll just add a placeholder for the cars list for now. But in the dynamic component, we'll import the useRouter hook from the next router. It allows us to access the query parameters from the URL.
In this example, the value is ID, but you can give it a name of whatever you want. And then we'll render that value out to the template. Now back in the browser, if we go to the cars URL, it renders out the cars component.
Then if we add any string after the cars URL, It renders out the dynamic component. Now one other thing you may have noticed in the pages directory is this API directory. So what is that all about?
The API directory is a special part of Next for setting up routes that will only apply to the server. That can be useful because the code you write here won't increase the client-side JavaScript bundle that needs to ultimately be sent over the network. We're not going to get into API routes in this video, but just know that it's a useful feature when you have work that needs to be done on the back end. or if you simply want to expose an API for your end users.
But now, let's shift our attention over to the most valuable feature in Next, which of course is data fetching. Next allows us to fetch data and render HTML on the server. And again, the benefit of doing that is that the end user gets rendered content quicker, and the content can be reliably crawled by search bots and social media link bots. Now when it comes to server rendering, there are two main options, static generation and server-side rendering. Static generation is also called pre-rendering because you generate all the HTML at build time.
It makes life very simple because you generate a bunch of HTML files, then upload them to a storage bucket or static host, and they can be delivered with very high performance over a CDN. But there's a couple of big trade-offs here. The first one is that your data may become stale.
If the data on the server changes, you need to rebuild and redeploy your site in order for those changes to be reflected. Another important trade-off to think about is scale. If your website has a million pages, it'll be very slow and difficult to pre-render all of them.
That makes static generation most well-suited for data that doesn't change often, and for sites that have a relatively low number of total pages. A good example would be a blog, because it might have a few hundred pages, and those pages likely don't change on a daily basis. Let's go ahead and take a look at how we might implement static generation in Next. In the car component, let's imagine we need to fetch data from an external source.
like a database or API. To simulate that for the demo, I've added a couple of JSON files to the public directory. We have a file that returns an array of IDs, then an individual response for each car, which contains an image and other data about the car. Now we can fetch this data for the car component by implementing the get static props function inside the component file. When you build your site, Next will automatically call this function, then send the result as props to the component itself.
What we want to do here is fetch the JSON for an individual car so it can be used in the HTML or UI for the car page. In this case, we need the ID from the URL to know which car was requested. We can get that information from the params argument in the function. Then from there, we'll use the fetch API to make a request to localhost to request the JSON file with that ID. We can then convert it to JSON.
Then the final step is to return an object that has a props property where each prop can then be accessed by the component. Up in the component code, we can destructure the car prop and then use it in the JSX, which I'm doing here by adding an image tag which relies on the data fetch by the server as the image source. Now if you're concerned about search engine optimization, you likely want to add an SEO-friendly title as well as meta tags to the head of the document. Next makes that very easy to accomplish by simply importing the head component.
Anything inside this component will be rendered out to the head of the document. Like in this case, we add a title with the car color and ID. And we could also add meta tags for Twitter and Facebook cards if we wanted to.
Now because we're working with a dynamic route, there's one other thing we have to keep in mind, and that's the fact that Next has no way of knowing how many pages we actually have associated to a dynamic route. In order to pre-render all the car IDs, Next needs to know those IDs in advance, and the way we provide that information is by implementing the getStaticPaths function. This function can also request data from an API or database, then its job is to return a paths object that contains an array with every route for this dynamic URL.
In this demo, we only have three routes, Tesla, Ford, and Lambo. We map those values to an array of objects, then return them from the function, along with additional options like the fallback behavior. Now if we go visit the app in the browser, we should see a fully rendered web page. It doesn't look any different than a regular React app.
However, if you open up the sources panel in Chrome DevTools, it'll show you the fully rendered HTML before it was touched by JavaScript. Notice how it contains the title and pre-rendered content, which is essential for SEO and sharing content on social media sites. So that's how you implement server-side generation. But another big strategy is server-side rendering. The big difference is that with SSR, the content is generated on a server when requested by the user.
This approach is ideal when data changes constantly, because it ensures the end user will always get the latest and greatest data from whatever your data source happens to be. However, it's far less efficient. because you need to have a server in place to respond to those requests, as opposed to caching everything on a global CDN. Imagine something like an eBay auction where you have millions of listings and those listings are changing all the time.
That's probably a good candidate for SSR. In any case, it's very easy to implement in Next. Back in our page file, we'll go ahead and implement another function called getServerSideProps. The only thing that actually changes in our code is the name of the function.
We can simply copy the body of the getStatic props function and paste it into our new function. It does the exact same thing, but does it on every request instead of at build time. Then we can comment out get static props and get static paths because we no longer need those functions. But the real beauty of Next is that we can apply both of these paradigms wherever we want in the application. We're not limited to one or the other.
I'm going to go ahead and wrap things up there. If there's anything you want to see in my full Next course, make sure to let me know in the comments. Thanks for watching, and I will see you in the next one.