Intro: Next is a React Front-End development framework. Next makes production a lot easier. Next builds on top of React and gives you extra features. Incredibly handy especially in terms of production. SSR and SSG opportunities (I like to think of it as SSR with GSP, SSR with GSSP or CSR). Not comparable to React itself. Next.js builds on top of React.
Client side routing can be fast and dynamic but one of the shortcomings of create-react-app is SEO. Crawlers can’t pick up your content. Next JS does this out of the box as the first page load is rendered server side then client side rendering takes over using hydration. Best of both worlds.
Routing is easier by putting page components in a pages folder. Don’t need to bring in React Router from react-router-dom and define all of your routes. Create a file about.js and make it a react component and put it in the pages folder and the page will automatically be rendered, (Like PHP where you create about.php and go to the route and it shows up). You can have dynamic parameters by structuring files a certain way.
Create API routes directly within the next file structure. This is one option, of course you can still have an Express backend or headless CMS. But with Next you can create API routes within Next file structure.
Out of the box TS and SASS. Just change file extensions.
Deployment: Host anywhere you can host a Node app or use VERCEL (company that created Next.js). You could use Heroku or cloud host. If you deploy as a Static Website you can host or deploy anywhere, including a cdn.
Create Next App: Need at least node 10.13. Start a project with npx utility called create-next-app folderName. Boilerplate application. Pretty simple/minimal base project. There is also a file structure to create manually without create-next-app if you prefer.
Files and Folders: Minimal which is nice. Webpack and Babel behind the scenes. Anything in the public folder is static. This public folder can be accessible/seen in the browser (favicon or other images).
So many ways to write CSS in Next including styled components but this course won’t get into that. Stylesheets kept in styles folder. Common to have a global.css file and then a specific CSS file for specific pages or components like Home.module.css. Can’t import global stylesheets directly into component so use anyName.module.css.
Pages and Routing: No 3rd party package or need to define your routes just drop in pages folder, (like php).
Head: You can pass meta tags (Good for SEO) by importing Head from ‘next/head.’ Custom titles, keywords, meta tags, etc. Single parent div or fragment. Now source code shows keywords you just added. Can have separate title for the about page or any other page and dynamic titles as well. Can create custom component you can pass in title via props. This is what makes next.js great for SEO.
Layout and CSS Modules: _app.js file wraps around all of your page components. Add a Layout.js component which contains header, footer, navbar, etc components.
Bring in global stylesheet here in _app.js. Create folder called components for components that are not pages. It’s convention to use lowercase for page-components and uppercase for other non-page-components that live in the components folder.
Create a Layout.js component and import a Layout.module.css file. Rename Home.module.css to Layout.module.css. If you want this to wrap around page components pass this as child. Now in App.js import Layout component and instead of returning directly.
Nav Component and Link: Create separate nav.js component and nav.module.css. Import stylesheet into component. Give it a className: navstyles.nav. Don’t use an “a tag” you bring in Link from next/link and use hrefs, (similar to what you would do with react-router-dom). Put above container. Return single element so wrap in empty angle brackets.
Create a Header: Display on every page. Create a stylesheet header.module.css and a new component header.js and inside have a React functional component and import header stylesheet.
Styled JSX: Can style CSS inline using styled JSX. This can get messy though but it’s good for conditional styles. As an example, If x is greater than 3 have the color be red, else have it be blue. Need to reload page when using conditional styling.
Custom Document: There is an _document.js file that you can create in your pages folder. Copy/paste content from the docs and tweak. This gives you a way to customize what can be seen in the view source. For example, you can add a lang attribute to the html tag. Probably don’t need this since you already have a head component but it has some uses.
Data Fetching: Add functions above or below main function, typically below. Export const and getStaticProps or GSSP.
GetStaticProps(): Fetch at build time. Async. In example Fetch data from 3rd party fake rest api called Json placeholder. Const res equal to await fetch(). Const articles await res.json. Return an object with props which is an object and then pass any data which in our case is articles. Now up in component function pass in {articles} as a prop.
Showing Data: To list out articles on homepage code
{articles.map((article) => and h3{article.title}h3))}
Cut and paste styles for grid and card and paste in separate file Article.module.css and import into components created in next section.
Instead of leaving articles in h3 create two separate components called ArticleList (for map function) and another called ArticleItem, (in React everything should be separate component).
Import ArticleList into pages/index.js and in JSX pass articles as prop set to {articles}.
Import Link into ArticleItem component. Receive prop {article}. Link href goes to /article/[id] as {`/article/${article.id}`}.
Have “a tag” with className {articleStyles.card} and inside “a tag” have an h3 with {article.title}→ which is title with an arrow and a -p element with {article.body} inside.
Now back in ArticleList leverage ArticleItem component and pass in (and receive) each individual article={article}.
Nested Routing: Go to pages and create folder called article and another folder called [id] with index.js file that will stand as your base article page.
To get id import next router by import {userouter} from next/router and above the return create a constant named router set equal to useRouter. Destructure id from router.query. You could use fetch inside useEffect or one of the data-fetching techniques Next provides and which this tutorial shows.
GetServerSideProps(): fetch data with every request (instead of getStaticProps which would fetch at build time).
Store in a constant named getServerSideProps an async function where you pass in context so you can get id of whatever is in url.
Create constant named res set to await fetch url in backticks to jsonplaceholder and leverage {context.params.id} to dynamically get id. Create a constant variable called article and set it to await res.json().
Return an object props which is an object and pass in article which we can then pass to page up at the top of the file. Now in the constant named article return update {id} to {article.id}. Have h1 with article.title and paragraph with article.body. link break. Link to go back to article listing so import Link from next/link and set href to “/”.
The site is pulling data each time the page is visited since we’re using GSSP. Keep it configured like this or use combo of GetStaticProps and GetStaticPaths to dynamically generate the paths you need.
GetStaticPaths(): Change getServerSideProps to getStaticProps and you will get an error that GetStaticPaths is required for dynamic SSG pages. Doing it this way is going to make your application much faster. Export const getStaticPaths set equal to an async arrow function. Make request to get all of the posts.
Return an object with paths:{params{id: “1”, id:”2″}} So above this returned object have a constant named ids and set it equal to articles.map() which takes in an article and returns article.id.
Just under that have a constant named paths that is set equal to ids.map() which takes in an id and returns an object params: that is set equal to an object id: which is equal to id.toString().
Now just have a path set to paths which can just be paths. Add fallback: false (which means if you go to something that doesn’t exist return 404 page). Now what should happen is that it generated all paths for us. So now you’ve got static generated pages for your dynamic paths.
Export a Static Website: Generate static website using what we created in previous lesson. Go to package.json add on to build script “&& next export” or create separate script. Start and stop server. Use script run build (next build && next export).
This builds for production so can deploy to vercel or other host. Also builds an “out folder” so you can serve as static site. (Optional but can install serve package globally. Say serve -s out folder -p 8000). Now we see static site served up for testing locally pre-deployment. If you were to delete everything but this “out folder” it would still work. Super fast. “Out folder” gets automatically added to git ignore file.
API Routes: An option for your backend if you are deploying this application to a server, (not just static build). In the api folder you have a default example hello.js file you can look at and delete. If you have used Express this will look familiar.
Create a folder named articles and a file inside that is named index.js. For every response or function you have a separate file, (Two in this project: one for a single article and one for all articles).
Where does the data come from? Anywhere really, you can make database calls in here, (Prisma as example with postgres) or MongoDB. This example project used dummy Json data for now by dragging file from repo into root of folder.
In api/articles index.js file import the dummy data file and export default function handler(req, res) and in block res.status(200).Json(articles). When you create something in api folder it will be automatic available from api/articles or whatever you named your folder.
And now you can fetch this data, which again can come from a file or db or whatever. Fetch a single article by creating another file in the api/articles folder called [id].js and we want to be able to go to home/articles/whatEvId and we can access that from req.query.id OR just destructure it since that is all we are bringing in so swap req for {query: {id}} to get access to id variable.
Filter out the specific article you want by that id by creating a constant named filtered set to articles.filter and article.id === id and if(filtered.length > 0) send res.status(200).Json(filtered[0]) else res.status(404).Json(message: `article with the ID of ${id} is not found`).
Using API Data: Go to pages/index and duplicate then comment out request for Json placeholder data. Swap out fetch for API/articles but you will get an error that only absolute urls are supported so you still have to add http://localhost:3000 in front of API/articles which will change when you deploy so create a folder called config and create index.js in there and create a constant variable named dev to see if we are in development by set equal to process.env.NODE_ENVIRONMENT !== ‘production’ and below that line export constant server = dev ? ‘Http/localhost:3000’ : ‘https://your website.com’ and save then import this in to your index.
Down in fetch use backticks and inside url reference ${server}/API/articles. Now if you click on an article you still see content from Json placeholder. Need to update article id index.js.
Duplicate and comment out both fetch functions and pull from api instead. At the top import {server} from ../../../config/ and down in getStaticProps function fetch have ${server}/Api/articles/${context.params.id}. In getstaticPaths function swap url for ${server}/API/articles. Now link from homepage should be pulling data from API.
Custom Meta Component: All pages if you want title custom title meta tags. Instead of importing Head on every page we want a default meta component to put in our layout component.
Create a new file called meta.js in the components folder and inside add a React functional component. Import Head from next/head and you want to have it take in some props {title, keywords, description}.
There are packages to use for stuff like this too next-seo.js is a good one.
Have the viewport and initial scale for Mobile. Have charSet utf-8. Have a favicon. Dynamic title description and keyword. Have default props Meta.defaultProps = title:”webdev newz”, keywords:”web development, programming”, description: “Get the Latest news”.
Now let’s bring this into our layout so inside layout.js import the meta component and right about nav in the JSX have meta component and in pages/index.js now you can get rid of head import in the JSX and save. In the about page do the same.
Now every page by default has these default props. If you want something different/custom say in about.js then you can import meta and pass in props with custom values to overwrite. In article pages to have article title as page title go to pages/article[id]/ index.js bring in meta component and pass in prop called title and set equal to {article.title}. You can pass description as prop as well and set to {article.excerpt}. Now in the source you will see this so very good for SEO.
In article/item you can have {article.excerpt} instead of {article.body} to show short excerpts on homepage instead of full content.