Nextjs
Nextjs
Next.js is a tool that helps developers build websites using React, a popular JavaScript
library. What makes Next.js special is that it can generate both static pages (like simple
websites that don't change often) and dynamic pages (like ones that update with new data).
It also helps make websites load faster and be more friendly to search engines like Google.
In short, Next.js makes building fast, modern websites easier by handling some of the
complex stuff behind the scenes, so developers can focus more on the design and
functionality.
React and Next.js are related but serve different purposes. Here's a breakdown of the
differences and why you might use Next.js even if you already have React:
1. React:
● What It Is:
○ React is a JavaScript library used for building user interfaces, particularly for
single-page applications (SPAs). It allows developers to create reusable UI
components.
● Features:
○ React is focused solely on the view layer of the application (the UI).
○ It uses a virtual DOM to efficiently update the UI in response to data changes.
○ React by itself doesn’t handle routing, server-side rendering (SSR), or SEO
optimizations.
2. Next.js:
● What It Is:
○ Next.js is a framework built on top of React that provides additional tools and
features to help developers build more complex applications, including those
that need to be optimized for search engines and perform better on the web.
● Features:
○ Server-Side Rendering (SSR): Next.js can render React pages on the
server before sending them to the browser, improving SEO and page load
times.
○ Static Site Generation (SSG): It can generate static HTML pages at build
time, making sites super fast.
○ Routing: Next.js comes with a built-in routing system, so you don't need a
separate library like React Router.
○ API Routes: You can create backend endpoints directly within a Next.js app,
making it easier to handle things like form submissions or fetching data.
○ File-Based Routing: In Next.js, the file structure in the pages directory
automatically defines your app's routes, simplifying navigation setup.
In Summary:
● React is great for building dynamic UIs and components.
● Next.js builds on React by adding features like SSR, SSG, routing, and backend
capabilities, making it ideal for more complex or SEO-focused web applications.
Using Next.js can save time and improve the overall performance and SEO of your web
application compared to using React alone.
1. What is Rendering?
Rendering is the process of generating the visual content of a website that you see in your
browser.
Where Rendering In the browser (client) On the server before sending to the
Happens browser
Initial Load Time Slower (wait for JavaScript Faster (HTML is ready immediately)
to load)
User Experience Smooth and fast after Immediate content, then interactive
initial load
Simple Analogy:
● Client-Side Rendering (React):
○ Imagine ordering a meal at a restaurant: You get a basic plate (HTML),
and then the chef (JavaScript) adds all the toppings and garnishes right at
your table. It takes time to see the full meal, but once it’s there, you can
customize it as you like.
● Server-Side Rendering (Next.js):
○ Imagine the chef prepares the entire meal in the kitchen and brings it to
your table fully cooked and plated. You see the complete meal
immediately, and then you can add any final touches if needed.
In Summary:
● React (CSR): Great for dynamic, interactive applications where SEO is less of a
priority.
● Next.js (SSR + CSR): Ideal for websites that need to load quickly, be SEO-friendly,
and still have dynamic, interactive features.
By using Next.js, you get the best of both worlds: the fast initial load and SEO benefits of
SSR, along with the interactive capabilities of React’s CSR.
Automatic Routing
Any URL is mapped to the filesystem, to files put in the pages
folder, and you don't need any configuration (you have
customization options of course).
Server Rendering
You can render React components on the server side, before
sending the HTML to the client.
Ecosystem Compatibility
Next.js plays well with the rest of the JavaScript, Node, and
React ecosystem.
This ensures your first page load is as fast as it can be, and
only future page loads (if they will ever be triggered) will send
the JavaScript needed to the client.
Prefetching
The Link component, used to link together different pages,
supports a prefetch prop which automatically prefetches
page resources (including code missing due to code splitting)
in the background.
Dynamic Components
You can import JavaScript modules and React Components
dynamically.
Static Exports
Using the next export command, Next.js allows you to export
a fully static site from your app.
TypeScript Support
Next.js is written in TypeScript and as such comes with an
excellent TypeScript support.
Next.js can generate a static site too, but I would not say it's
its main use case.
Make sure that you have the latest version of Node. Check
with running node -v in your terminal, and compare it to the
latest LTS version listed on https://nodejs.org/.
After you install Node.js, you will have the npm command
available into your command line.
Now that you have Node, updated to the latest version, and
npm, we're set!
npx create-next-app
mkdir nextjs
cd nextjs
mkdir firstproject
cd firstproject
Now use the npm command to initialize it as a Node project:
npm init -y
The -y option tells npm to use the default settings for a project,
populating a sample package.json file.
{
"name": "firstproject",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"next": "^9.1.2",
"react": "^16.11.0",
"react-dom": "^16.11.0"
}
}
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
Tip: use "dev": "next -p 3001", to change the port and run,
in this example, on port 3001.
Now using the terminal, run npm run dev to start the Next
development server.
The React app will be launched on the client, and will be the
one powering interactions like clicking a link, using client-side
rendering. But reloading a page will re-load it from the server.
And using Next.js there should be no difference in the result
inside the browser - a server-rendered page should look
exactly like a client-rendered page.
<!DOCTYPE html>
<html>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,minimum-
scale=1,initial-scale=1" />
<meta name="next-head-count" content="2" />
<link rel="preload" href="/_next/static/development/pages/index.js?
ts=1572863116051" as="script" />
<link rel="preload" href="/_next/static/development/pages/_app.js?
ts=1572863116051" as="script" />
<link rel="preload" href="/_next/static/runtime/webpack.js?
ts=1572863116051" as="script" />
<link rel="preload" href="/_next/static/runtime/main.js?
ts=1572863116051" as="script" />
</head>
<body>
<div id="__next">
<div>
<h1>Home page</h1></div>
</div>
<script
src="/_next/static/development/dll/dll_01ec57fc9b90d43b98a8.js?
ts=1572863116051"></script>
<script id="__NEXT_DATA__"
type="application/json">{"dataManager":"[]","props":{"pageProps":
{}},"page":"/","query":
{},"buildId":"development","nextExport":true,"autoExport":true}</
script>
<script async="" data-next-page="/"
src="/_next/static/development/pages/index.js?ts=1572863116051"></
script>
<script async="" data-next-page="/_app"
src="/_next/static/development/pages/_app.js?ts=1572863116051"></script
>
<script src="/_next/static/runtime/webpack.js?ts=1572863116051"
async=""></script>
<script src="/_next/static/runtime/main.js?ts=1572863116051"
async=""></script>
</body>
</html>
Then those 4 files are loaded at the end of the body, along
with
/_next/static/development/dll/dll_01ec57fc9b90d43b98a8.js
(31k LOC), and a JSON snippet that sets some defaults for
the page data:
When this is the case, our page can be even faster because it
will be served statically as an HTML file rather than going
through the Node.js server that generates the HTML output.
Once you have installed the React Developer Tools, you can
open the regular browser devtools (in Chrome, it's right-click
in the page, then click Inspect) and you'll find 2 new panels:
Components and Profiler.
If you move the mouse over the components, you'll see that
in the page, the browser will select the parts that are
rendered by that component.
If you select any component in the tree, the right panel will
show you a reference to the parent component, and the
props passed to it:
You can easily navigate by clicking around the component
names.
You can click the eye icon in the Developer Tools toolbar to
inspect the DOM element, and also if you use the first icon,
the one with the mouse icon (which conveniently sits under
the similar regular DevTools icon), you can hover an element
in the browser UI to directly select the React component that
renders it.
You can use the bug icon to log a component data to the
console.
You can create a pages/hey/ho page, and that page will show
up on the URL http://localhost:3000/hey/ho.
Try going and viewing the source of the page, when loaded
from the server it will list
/_next/static/development/pages/blog.js as one of the
bundles loaded, and not
/_next/static/development/pages/index.js like in the home
page. This is because thanks to automatic code splitting we
don't need the bundle that serves the home page. Just the
bundle that serves the blog page.
Normal HTML links within pages are done using the a tag:
<a href="/blog">Blog</a>
We import it:
In the file name, [id] inside the square brackets means that
anything that's dynamic will be put inside the id parameter of
the query property of the router.
The dynamic part can also just be a portion of the URL, like
post-[id].js.
return (
<>
<h1>Blog post</h1>
<p>Post id: {router.query.id}</p>
</>
)
}
{
"test": {
"title": "test post",
"content": "Hey some post content"
},
"second": {
"title": "second post",
"content": "Hey this is the second post content"
}
}
Now we can import it and lookup the post from the id key:
return (
<>
<h1>{post.title}</h1>
<p>{post.content}</p>
</>
)
}
return (
<>
<h1>{post.title}</h1>
<p>{post.content}</p>
</>
)
}
And if you view source, there is that empty <p> tag in the
HTML:
We'll soon fix this issue that fails to implement SSR and this
harms both loading times for our users, SEO and social
sharing as we already discussed.
<ul>
{Object.entries(posts).map((value, index) => {
return <li key={index}>{value[1].title}</li>
})}
</ul>
</div>
)
<ul>
{Object.entries(posts).map((value, index) => {
return (
<li key={index}>
<Link href='/blog/[id]' as={'/blog/' + value[0]}>
<a>{value[1].title}</a>
</Link>
</li>
)
})}
</ul>
</div>
)
Prefetching
I mentioned previously how the Link Next.js component can
be used to create links between 2 pages, and when you use
it, Next.js transparently handles frontend routing for us, so
when a user clicks a link, frontend takes care of showing the
new page without triggering a new client/server request and
response cycle, as it normally happens with web pages.
There's another thing that Next.js does for you when you use
Link.
Any other Link tag not in the viewport will be prefetched when
the user scrolls and it
Using next/router
We already saw how to use the Link component to
declaratively handle routing in Next.js apps.
The ones you'll likely use the most are push() and prefetch().
router.push('/login')
router.prefetch('/login')
Full example:
useEffect(() => {
router.prefetch('/login')
})
}
You can also use the router to listen for route change events.
return (
<>
<h1>{post.title}</h1>
<p>{post.content}</p>
</>
)
}
we got this error:
Post.getInitialProps = () => {
//...
}
● /blog/test
CSS
How do we style React components in Next.js?
<style jsx>{`
`}</style>
<style jsx>{`
h1 {
font-size: 3rem;
}
`}</style>
<style jsx>{`
h1 {
font-size: 3rem;
}
`}</style>
</div>
)
export default Index
<style jsx>{`
h1 {
font-size: ${props.size}rem;
}
`}</style>
</div>
)
After restarting the Next app, you can now import CSS like
you normally do with JavaScript libraries or components:
import '../style.css'
You can add any HTML tag you'd like to appear in the <head>
section of the page.
But I found this works only for simple cases, where you don't
need to call getInitialProps() on a page.
Why?
API Routes
In addition to creating page routes, which means pages are
served to the browser as Web pages, Next.js can create API
routes.
API routes live under the /pages/api/ folder and are mapped
to the /api endpoint.
[
{
"comment": "First"
},
{
"comment": "Nice post"
}
]
You can make use of any Micro middleware in our API routes
to add more functionality.
}
and add the server-side code in that block.
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
We used npm run dev up to now, to call the next command
installed locally in node_modules/next/dist/bin/next. This
started the development server, which provided us source
maps and hot code reloading, two very useful features
while debugging.
Then you can run npm run start to start the production server
locally:
Deploying on Now
In the previous chapter we deployed the Next.js application
locally.
The best way to start using Now is by using the official Now
CLI:
now login
Once this is done, from the Next.js project root folder run
now
and the app will be instantly deployed to the Now cloud, and
you'll be given the unique app URL:
Once you run the now program, the app is deployed to a
random URL under the now.sh domain.
● https://firstproject-2pv7khwwr.now.sh
● https://firstproject-sepia-ten.now.sh
● https://firstproject.flaviocopes.now.sh
Why so many?
If you visit the URL, you will see the app deployed to
production.
You can configure Now to serve the site to your own custom
domain or subdomain, but I will not dive into that right now.
Like this:
{
"name": "firstproject",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"analyze": "cross-env ANALYZE=true next build",
"analyze:server": "cross-env BUNDLE_ANALYZE=server next build",
"analyze:browser": "cross-env BUNDLE_ANALYZE=browser next build"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"next": "^9.1.2",
"react": "^16.11.0",
"react-dom": "^16.11.0"
}
}
module.exports = withBundleAnalyzer({})
We import it in pages/blog/[id].js:
...