My take on Next.js
Hi! My name is Luciano Serruya Aloisi, I'm a 23-years old software developer from Trelew, Chubut, Argentina 🇦🇷. I've been wanting to start writing for some time now, and having such an amazing platform as Collected Notes really made my mind about it, so here it goes!
In this first article, I'd like to write about Next.js, the React framework. But, how come? some may ask to themselves; isn't React a framework already?. Well, not exactly. As it says right in React.js' home page, is a JavaScript library for building user interfaces. The confusion arises because it can be used as a framework, scaffolding your app with create-react-app
. In such an app, you can write your components using JSX, display several "pages" using react-router, handle your app's state with Redux, validate your forms using Formik, and so on. As you may have noticed, I named several others libraries besides React for building your React app. So, to move on with the article, I want to make clear that React is a library that does one and one thing only, and that is helping you build user interfaces (and it does it really really well).
Okay great, we have create-react-app for ours React apps, why do we need a framework for our UI library then?. That's a valid question as well, yes. Although a React app created with create-react-app
already provides a lot of setup, it may not be the best option for some scenarios.
Lets suppose you are building a platform for knowledge sharing, where users can create entries about a certain topic and some other s users can update it (yes you are building another Wikipedia, I know). The way a traditional React app works (and not only React apps, Vue and Angular apps works this way as well) is serving only a single HTML file with one or more JavaScript files to render your whole app. This is what is called a Single Page Application (SPA), where the server only responds to HTTP requests with a single file and page routing is done via JavaScript on the browser.
Okay, so you have your brand new app which is already deployed and working, but you try searching some entry you know is on your site in Google and you can't find anything, or if you are lucky enough you do find something, but really deep into Google's pages. Google is merciful enough to at least show your site in some entries, but you also tried with Bing and DuckDuckGo with even worse luck, your site doesn't even appear on other search engines. What is going on? - you say to yourself. The thing is, because your app is a single HTML file with no content on it, but content is rendered after it is loaded into the client's browser, search engines' crawlers cannot index your app's pages properly - I won't dive deeper into how crawlers work because I don't really know about the topic, but you can think of them as programs that constantly fetch web pages and build some sort of index (the same kind you can find in a book) which indicates where to go if you are looking for a specific term.
That's a problem, because you already built your site as a SPA but you need search engines' crawlers to be able to index your content so it can be easily found when searching for it - in other words, you need to do some Search Engine Optimization (SEO) on your site. One of the most typical solutions to tackle this issue is doing Server-Side Rendering (SSR), that is rendering your content on the server, and serving your markup already rendered. But again, you have a React SPA, which renders content on the browser, so what can you do?
Here is when Next.js comes into play. It would be wrong from my side to say that SSR is the only thing that Next.js can give you (it offers plenty of features), but in this article I'll be only focusing on it. One of the biggest selling points of Next.js is its ability to render your React components on the server (a Node.js server), and respond with that markup to any HTTP requests that it receives. This will be a major improvement when it comes to searching your site in several search engine (it won't be instant-quick though, some time will pass before crawlers index your content).
Sounds pretty good, right? It is, but before jumping in the Next.js boat and rush to migrate your React app/s to a Server-Side rendered version, bear in mind that a migration of such sort won't be that easy. There are three key points I would like to talk about:
File structure
In Computer Science and Software Development, one of the most typical definition of a framework is some code that you don't directly call, but it calls your code. Using this pretty vague description of what a framework is, we can clearly tell that Next.js is a framework. Next.js implements what is called a "file-based routing", so you can define your routes creating a different file per route inside the pages
directory (or src/pages
) . For example, if you want an about
and a contact
page, you would create an about.js
and a contact.js
files.
Migrating to Next.js wouldn't mean a great effort if you already had a views
or a pages
directory in your React app. Of course you can keep your components
directory or whatever other file structure you were using, the only rule you have to follow is the page-components-go-in-pages-directory.
Data fetching
This one is quite interesting and, in my opinion, one of the best features Next.js provides. In your SPA built with React, you most surely fetch your data in the componentDidMount
method or using the useEffect
hook. With Next.js, as you want your component to be populated with data before reaching the client's browser, the framework offers a method called getServerSideProps
(Next.js 9.3+) in which you can get all the data you need to render your component. This means making HTTP requests, querying a database, reading a file, and so on. Whatever data this function returns, will be passed as props to your page component. Two take-away points:
- Only page components should export a
getServerSideProps
function - won't work with non-page components - Data meant to be passed as props to your page component should be under the
props
key in the object you are returning fromgetServerSideProps
export async function getServerSideProps(context: GetServerSidePropsContext) {
.
.
.
return {
props: {
<YOUR_DATA>
}
};
(oh as you may have noticed, Next.js supports TypeScript out of the box. Just create a empty tsconfig.json
at root level and rename your .js
file for .tsx
)
Having this method comes really handy, as you don't need to have an API endpoint for fetching your initial data - you just query your database directly in the getServerSideProps
method
Deployment
Once you have your Next.js app, how can you deploy it? Next.js allows you to generate static files out of all your pages, so you can deploy them to a static hosting service. One thing to keep in mind is that if you choose this approach, your static files will be generated at build time, which means they will fetch any server-side data at build time (there is a whole section in the docs that talks about generating static file with and without external data).
If build-time data-fetching is not what you are looking for (for example, if you want to query a database every time a page is visited), you should consider deploying your site as a Node.js app to a VPS, as a Docker container, using a Function-as-a-Service provider (you need a custom server for this approach), and so on.
There is yet another catch with Next.js (well actually, with Server-Side Rendered JavaScript components libraries/frameworks) when it comes to rendering components. I said before that your UI components are rendered in the server whenever a HTTP request comes in. But that's not the end of it, because when the app is loaded in the client's browser, components are rendered again (so they are rendered twice, once in the server, once in the browser). To demonstrate this point, I've developed a demo app in Next.js which this is the only thing it shows
export default function Home() {
return <h1>{Math.random()}</h1>;
}
It has a single page, and the only thing it shows is a random number. As this component will be executed twice, the server will generate a random number and render it inside an h1
element. Then, when the page hits the client's browser, the component will be executed once again, generating yet another random number. To check that the displayed number is not the same the server generated, check the page's source (Ctrl+U
in Chrome) and look for the h1
element, you should see a different floating number.
Conclusion
In this article I talked about how a SSR page can help you with SEO, and how Next.js helps you to achieve that for your React apps. I also named a few caveats to bear in mind while (or if) migrating your React SPA to a Next.js SSR app. Next.js may not be the end-all, and maybe not the best option for your situation either, but it is nonetheless a great framework with a lot of out-of-the-box features that you shouldn't stop checking!
Hope you liked it!
📧 lucianoserruya (at) gmail (dot) com