Next.js enhances your React apps and adds more features.
It has lots of built-in feature that help you solve common problems & give clear guidance on how to use those features to you
There are certain problems which you will need to solve for almost all production-ready React apps. NextJS solves these problems.
SSR(server-side rendering)
When we do client side rendering and send request to fetch data, It needs time to get data from server to client. This may occur bad user experince.
If that process can be pre-rendered on server , user doesn't have to experince loading state and Search engine can check your page content because server uploaded everything first before page rendered to client.
In conclusion, Next.js is great for SEO and initial load.
File-based Routing
React router does is changing what's visible on the screen based on the URL without sending a extra request to a server.
So we created pages and components in code.
But Next.js gets rid of that in-code route definition.
Instead, Next.js works with files to define route.
For example,
pages
-> posts
-> index
-> products
-> index
These file directory will be route as it is.
Next.js> npx create-next-app
npx: installed 1 in 1.437s
√ What is your project named? ... basic-next
Creating a new Next.js app in C:\Users\junsb\OneDrive\바탕 화면\Frontend portfolio\react\14-expert-Next.js\basic-next.
pages(dir)
-> index.js : "http://domain.com/"
-> news.js : "http://domain.com/news"
pages(dir)
-> index.js : "http://domain.com/"
news(sub-folder)
-> index.js : "http://domain.com/news"
If you set sub folder , you should give file name as index (because it is initialization in sub-folder)
For dynamic routes, we should set filename in square brackets.
For example,
news(dir)
-> index.js : '/news'
-> [newsId] : '/news/:newsId'
Then How to get this params?
import { useRouter } from "next/router";
function DetailPage() {
const router = useRouter();
console.log(router.query.newsId);
return <h1>Something</h1>;
}
export default DetailPage;
import Link from "next/link";
function NewsPage() {
return (
<Fragment>
<h1>news</h1>
<ul>
<li>
<Link href="/news/nextjs">Next js is good</Link>
</li>
<li>
<Link href="/news/nextjs">Nest js is good</Link>
</li>
</ul>
</Fragment>
);
}
const router = useRouter();
function showDetail() {
router.push(`/${props.id}`);
}
function HomePage(props) {
return <MeetupList meetups={props.meetups} />;
}
export async function getStaticProps() {
// fetch data from an API
return {
props: {
meetups: dummyMeetup
}
}
}
If you export getStaticProps(this name is reserved by Next), it will run before HomePage function rendered.
The important thing is you should return object and In that object, you should return props property to use in your component after pre-rendering.
In above example, i gave dummy meetup data as props. So HomePage function can access dummy data when they start.
If you execute this line in terminal, you can check more information.
'npm run build'
A problem is our data which is pre-rendered could be outdated after deploying. Even though we add some new data, new product, pre-generated page doesn't know about that fact.
To solve this , if you give a number to getStaticProps function
export async function getStaticProps() {
// fetch data from an API
return {
props: {
meetups: dummyMeetup
},
revalidate: 10
}
}
It will be generated every coupl of seconds which you set.
Set the number according to frequency of data changing.
This function will not run during the build process(for deploying)
but instead always on the server after deployment.
Hence, there is no need to revalidate like static generation because it will update for every incoming request.
You also can set parameter to access request and response.
export async function getServerSideProps(context) {
const req = context.req
const res = context.res
return {
props: {
meetups: dummyMeetup,
},
};
}
As a result,
Low frequency request-> Static generation
High frequency request -> SSR
export async function getStaticPaths() {
return {
fallback: false,
paths: [{ params: { meetupId: "m1" } }, { params: { meetupId: "m2" } }],
};
}
you should give 'fallback' and 'paths' property.
Fallback check whether paths containes all supported value or not (in this example, we are using hard-coded supported value. so fallback value is false)
And in paths property, you can set dynamic segment with params.
In pages/api/new-meetup.js
import { Db, MongoClient } from "mongodb";
async function handler(req, res) {
if (req.method === "POST") {
const data = req.body;
const client = await MongoClient.connect(
"mongodb+srv://yechan1:junyc1010!@nodeexpressprojects.iwbad.mongodb.net/Meetups?retryWrites=true&w=majority"
);
const db = client.db();
const meetupsCollection = db.collection("meetups");
const result = await meetupsCollection.insertOne(data);
client.close();
res.status(201).json({ result, msg: "meetup inserted" });
}
}
export default handler;
When you use this api, you will give "api/" as an endpoint.
import Head from "next/head";
return (
<Fragment>
<Head>
<title>Add new meetups</title>
<meta name="description" content="Add your own meetups"></meta>
</Head>
<NewMeetupForm onAddMeetup={addMeetupHandler} />;
</Fragment>
);