Next.
js 14 & React - The Complete Guide
Section 1: Getting Started
1. Welcome To The Course!
2. What is NextJS? Why Would You Use It?
• NextJS is a fullstack React framework, i.e, it is built up on ReactJS which
simplifies building fullstack applications.
1. Key Features & Benefits Of NextJS
• Fullstack Apps: NexyJS allows us to build fullstack applications with React.
It blends front-end and back-end to help build complex applications in
one project and in one programming language, i.e, JavaScript and also
use only one framework or library.
• Folder And File Based Routing: NextJS helps with setting up routes using
folder and file system instead of configuring them in code, which gives us
a huge advantage of having no code-based configuration or extra
packages for routing.
• Server Side Rendering: NextJS renders all the content that is visible on
the screen on the server itself, which means that the HTML document
already includes the content to be presented on the screen instead of
being mostly empty and populated on the client-side, which also means
that the search engine crawlers see that finished content as well.
1. Creating a First NextJS App
2. NextJs vs “Just React” - Analyzing The NextJs Project
• ReactJS, by default, is a client-side JavaScript library, which means it runs
in a browser and edits and manipulates the page in the browser. We can
update the state of the page after it is reloaded without having to fetch a
new page. To its disadvantage, search engine crawlers do not see the
actual page content if they visit the page for the first time. But it is not
the case with NextJs, it is a fullstack application and not just a client-side
application.
1. Editing The first App
2. Pages Router vs App Router - One Framework, Two Approaches
• Pages Route: Has been around for many years, very stable, used in many
existing NextJS projects and it allows you to build feature-rich fullstack
apps with React.
• App Router: Introduced with NextJS 13, Marked as stable but still
relatively new & partially buggy. Supports modern Next & React features
and is the future of NextJs.
1. How To Get The Most Out Of This Course
2. Learning Community & Course Resources
Section 2: Optional: React Refresher
1. Using The Code Snapshots
2. Module Introduction
3. What Is React & Why Would You Use It?
• React is a JavaScript library for building highly interactive user interfaces
(UI). In the case of the raw Vanilla JavaScript code, we have to code step-
by-step to tell the browser step-by-step when and where what should
happen on the screen, adopting the Imperative approach. Where in the
case of React, we write Declarative code where we simply write the UI
that should be rendered on the screen and blend some event-listeners or
values into the HTML code. While in React, we can also describe different
states and also when a different state should be active. ReactJS then
generates the appropriate instructions for the browser under the hood,
saving us the trouble.
1. React Project - Requirements
2. Creating React Projects
3. Our Starting Project
4. Understanding How React Works
• [Link]: It contains the JSX code for content that populates the web-page.
Its content are called components, which are just functions that return
JSX code.
• [Link]: It is the main entry file of the entire directory. The code in this
file is executed first when the web-site is being loaded in the browser. Its
content is responsible for populating the web-page with the ReactJS code
which is rendered as HTML code while checking for sub-optimal code as
well as taking care of future changes that may have to be made.
• [Link]: It helps manage the dependencies of your project, i.e, the
third-party packages used by your project. It also manages the packages
for your front-end projects where you don’t use NodeJS.
1. Building A First Custom Component
• Custom components can not start with lower case characters as React
would then treat them as Default components which they are not.
1. Outputting Dynamic Values
2. Reusing Components
• A component can return a maximum of only one element. Though that
element may contain several children components.
1. Passing Data to Components with Props
2. CSS Styling & CSS Modules
• We use [Link] for writing particular component’s CSS instead of just
writing its CSS in [Link] because we want to avoid conflicting CSS
classes from taking place. Infact CSS Modules will transform the class
names to keep them from conflicting in the final HTML code.
1. Exercise & Another Component
2. Preparing the App For State Management
3. Adding Event Listeners
4. Working with State
• React executes your functions then takes the JSX returned by those
functions that is to be rendered on the screen. Hence, even if you often
change some variable’s value within your JSX code, that won’t be picked
up by React because the JSX code is only taken once as a snapshot when
the component function is executed for the first time. If the function were
to be re-executed by React, the variable’s value would be updated but,
React does note by default, randomly, execute functions just because you
changed some variable’s value or just because you have an event
listener in there.
1. Lifting State Up
• If you have states that is being manipulated in component ‘A’ but is
needed in component ‘B’, then you should lift the state up to a
component that has access to both the components that need the state.
1. The Special “children” Prop
• If you wrap components within a custom component, by default, React
does not know where to put that wrapped content inside the wrapping
[Link] have to tell React where that wrapped content should go.
1. State & Conditional Content
2. Adding a Shared Header & More State Management
3. Adding Form Buttons
4. Handling Form Submission
5. Updating State Based On Previous State
• We should use a function for updating a state instead of just updating the
array itself, because internally, React does not actually execute your
state updating functions instantly, at least it is not guaranteed to do so,
but it schedules those state updates in case you have multiple state
updates after you potentially update your state based on some old state.
Thus, calling a function on every state update is a better way even if you
have multiple pending state updates.
1. Outputting List Data
2. Adding a Backend to the React SPA
3. Sending a POST HTTP Request
4. Handling Side Effects with useEffect()
• Where and whenever we want to effectively cause a side effect, i.e,
trigger an action that does not directly trigger our JSX code, i.e, anything
that is not related to rendering the UI, we use useEffect(). It prevents
causing an infinite loop that may be caused in cases involving fetching
data and updating data simultaneously. It prevents the infinite loop by
making sure that the function held within it does not execute every time
the parent function executes. The execution of the function held within is
determined by the dependencies held within its array, where the
dependency may be any variable or function defined outside of
useEffect() and whenever there is a change in its value, the function is
executed. In the case of an empty array, i.e, when there are no
dependencies, the function only executes once, i.e, technically after the
parent function is executed for the first time.
1. Handle Loading State
2. Understanding & Adding Routing
• We can introduce routing in React despite it being a single page
application (SPA) by using React Router package. Though the routing
takes place on the client-side rather than on the server.
1. Adding Routes
2. Working with Layout Routes
3. Refactoring Route Components & More Nesting
4. Linking & Navigating
5. Data Fetching via loader()s
• loader(): It expects to get a function as a value and React executes that
function whenever that route gets activated, which is whenever an
element or component is supposed to be rendered. That function is used
to load and prepare any data that might be needed by that component or
any other component used as part of that route, i.e, nested component
used within that component.
1. Submitting Data with action()s
• action(): It also expects to get a function just like loader(). This function,
however, executes when a form is submitted in that route.
• Form: When used, React router, handles the form submission, prevents
the browser's default of sending a request but will still gather all the input
data, still generate an object with that data for us and call the action()
that is assigned to the route which contains the Form. In the post method,
no actual post request is sent anywhere because it is all client-side code,
but what React Router does behind the scene is that it will generate a
request object with that form data included in it and will give that request
object a method which could be used in action() to find out which Form
was submitted when that action() was triggered in case we have multiple
forms that belong to the same route with the same action.
• redirect(): It generates a response object which is returned by action()
and if you return such a response object, React Router will look into the
object and see if it is a redirect response, the React Router will simply
move to that different route to which you are trying to redirect.
1. Dynamic Routes
2. Module Summary
3. IMPORTANT -- LEGACY CONTENT BELOW
4. Module Introduction
Section 3: NextJS Essentials (App Router)
1. Module Introduction
2. Starting Setup
3. Understanding File-based Routing & React Server Components
• app: It is in this folder that you setup the different pages that you want to
have and that is why you find a [Link] file in there.
• [Link]: It is a reserve file name which tells NextJS that it should render a
page. The content held within it is a server component. It returns a JSX
code that is sent over the wire to the browser to be rendered as an HTML
code.
1. Adding Another Route via the File System
2. Navigating Between Pages - Wrong & Right Solution
• If we are already on a page and then we navigate around, NextJS allows
us to actually stay in a single page application and update the UI with the
help of the client side JavaScript code. The content of the next page will
still be pre-rendered on the server, but it will then be updated on the
client side by client side JavaScript code. Thus, we get the best of both
worlds, i.e, a highly interactive reactive client side application, once it is
active but a finished page being served if you are visiting the page for the
first time.
1. Working with Pages & Layouts
• [Link]: Just as the [Link] file defines the content of a page, the
[Link] file defines the shell around one or more pages. It is the layout
in which the page will be rendered. It comprises of a component that
returns the HTML skeleton of a page. It populates the body by the content
defined within the [Link] file.
• metadata: All the content that goes into the head is set by metadata or
automatically behind the scenes by NextJS.
1. Reserved File Names, Custom Components & How To Organize A NextJS
Project
2. Reserved Filenames
As you already learned, there are some reserved filenames when working
with NextJS.
Important: These filenames are only reserved when creating them inside of
the app/ folder (or any subfolder). Outside of the app/ folder, these filenames
are not treated in any special way.
Here's a list of reserved filenames in NextJS - you'll, of course, learn about
the important ones throughout this section:
•
[Link] => Create a new page (e.g., app/about/[Link] creates
a <your-domain>/about page)
•
•
[Link] => Create a new layout that wraps sibling and nested pages
•
•
[Link] => Fallback page for "Not Found" errors (thrown by sibling or nested
pages or layouts)
•
•
[Link] => Fallback page for other errors (thrown by sibling pages or nested pages or
layouts)
•
•
[Link] => Fallback page which is shown whilst sibling or nested pages (or layouts)
are fetching data
•
•
[Link] => Allows you to create an API route (i.e., a page which does NOT return
JSX code but instead data, e.g., in the JSON format)
•
You also find a list with all supported filenames & detailed explanations in the
official docs: [Link]
1. Configuring Dynamic Routes & Using Route Parameters
• []: It makes the same [Link] file within active for different path segment
values. It tells NextJS that we want some path segment after the parent
path, but we do not know the exact value of the path segment yet.
1. Onward to the Main Project: The Foodies App
2. Exercise: Your Task
3. Exercise: Solution
4. Revisiting The Concept Of Layouts
5. Adding a Custom Component To A Layout
• .src: The imported images in Next projects are objects where the path to
an image is stored under the src property.
1. Styling NextJS Project: Your Options & Using CSS Modules
2. Optimizing Images with the NextJS Image Component
• Image: NextJS adds a few extra attributes to the default img tag. For
instance, loading=“lazy” makes sure that the image is only loaded if it is
really visible. On the other hand srcset attribute makes sure that
differently sized images are loaded depending on the view port of the
device at hand. In addition, it automatically serves the image in the best
file format for the browser being used by the user.
1. Using More Custom Components
2. Populating The Starting Page Content
3. Preparing an Image Slideshow
4. React Server Components vs Client Components - When To Use What
• NextJS knows react server components or server components and client
components. NextJS, by default, renders all components on the server.
Even if you are on a single page application and are navigating around,
all the components will still be rendered on the server on the back-end
and then, in the end, a finished HTML code is sent to the client to be
rendered there.
• React Server Components: Components that are only rendered on the
server. By default, all React components (in NextJS) are React Server
Components (RSC). Advantages being, less client-side JS and is great for
Search Engine Optimization (SEO).
• Client Components: Components that are pre-rendered on the server but
then also potentially on the client. Opted-in via “use client” directive.
Advantages being, client-side interactivity.
1. Using Client Components Efficiently
2. Outputting Meals Data & Image With Unknown Dimensions
• fill: You can use fill prop instead of setting a width and height whenever
you have an image where you do not know the dimensions in advance.
Here in advance means on the server.
1. Setting Up A SQLite Database
2. Fetching Data By Leveraging NextJS & FullStack Capabilities
3. Adding A Loading Page
4. Using Suspense & Streamed Responses For Granular Loading State
Management
• Suspense: It is a component provided by React that allows you to handle
loading states and show fallback content until some data or resource has
been loaded.
1. Handling Errors
2. Handling “Not Found” States
3. Loading & Rendering Meals Details via Dynamic Routes & Route
Parameters
4. Throwing Not Found Errors For Individual Meals
5. Getting Started with the “Share Meal” Form
6. Getting Started with a Custom Image Picker Input Component
7. Adding an Image Preview to the Picker
8. Improving the Image Picker Component
9. Introducing & User Server Actions for Handling Form Submissions
• use server: It makes a function execute only on a server.
1. Sorting Server Actions in Separate Files
2. Creating a Slug & Sanitizing User Input for XSS Protection
3. Storing Uploaded Images & Storing Data in Database
4. Managing the Form Submission Status with useFormStatus
5. Adding Server-Side Input Validation
6. Working with Server Action Responses & userFormState
7. Building For Production & Understanding NextJS Caching
8. Triggering Cache Revalidations
• revalidatePath: This function tells NextJS to re-validate the cache that
belongs to a certain route path. Its second parameter can be set to page
to re-validate only that page or layout to re-validate all its nested pages.
1. Don’t Store Files Locally On The Filesystem!
2. Bonus: Storing Uploaded Images In The Cloud (AWS S3)
As explained in the previous lecture, storing uploaded files (or any other files
that are generated at runtime) on the local filesystem is not a great idea -
because those files will simply not be available in the running NextJS
applications.
Instead, it's recommended that you store such files (e.g., uploaded images)
via some cloud file storage - like AWS S3.
AWS S3 is a service provided by AWS which allows you to store and serve
(depending on its configuration) files. You can get started with this service for
free but you should check out its pricing page to avoid any unwanted
surprises.
In this lecture, I'll explain how you could use AWS S3 to store uploaded users
images & serve them on the NextJS website.
1) Create an AWS account
In order to use AWS S3, you need an AWS account. You can create one here.
2) Create a S3 bucket
Once you created an account (and you logged in), you should navigate to
the S3 console to create a so-called "bucket".
"Buckets" are containers that can be used to store files (side-note: you can
store any files - not just images).
Every bucket must have a globally unique name, hence you should become
creative. You could, for example, use a name like <your-name>-nextjs-demo-
users-image.
I'll use maxschwarzmueller-nextjs-demo-users-image in this example here.
When creating the bucket, you can confirm all the default settings - the
name's the only thing you should set.
3) Upload the dummy image files
Now that the bucket was created, you can already add some files to it
=> The dummy images that were previously stored locally in
the public/images folder.
To do that, select your created bucket and click the "Upload" button. Then
drag & drop those images into the box and confirm the upload.
Thereafter, all those images should be in the bucket:
4) Configure the bucket for serving the images
Now that you uploaded those dummy images, it's time to configure the
bucket such that the images can be loaded from the NextJS website.
Because, by default, this is not possible! By default, S3 buckets are "locked
down" and the files in there are secure & not accessible by anyone else.
But for our purposes here, we must update the bucket settings to make sure
the images can be viewed by everyone.
To do that, as a first step, click on the "Permissions" tab and "Edit" the "Block
public access" setting:
Then, disable the "Block all public access" checkbox (and with it, all other
checkboxes) and select "Save Changes".
Type "confirm" into the confirmation overlay once it pops up.
That's not all though - as a next (and final step), you must add a so-called
"Bucket Policy". That's an AWS-specific policy document that allows you to
manage the permissions of the objects stored in the bucket.
You can add such a "Bucket Policy" right below the "Block all public access"
area, still on the "Permissions" tab:
Click "Edit" and insert the following bucket policy into the box:
• {
• "Version": "2012-10-17",
• "Statement": [
• {
• "Sid": "PublicRead",
• "Effect": "Allow",
• "Principal": "*",
• "Action": [
• "s3:GetObject",
• "s3:GetObjectVersion"
• ],
• "Resource": [
• "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
• ]
• }
• ]
• }
Replace DOC-EXAMPLE-BUCKET with your bucket name (maxschwarzmueller-
nextjs-demo-users-image in my case).
Then, click "Save Changes".
Now the bucket is configure to grant access to all objects inside of it to
anyone who has a URL pointing to one of those objects.
Therefore, you should now of course not add any files into the bucket that
you don't want to share with the world!
To test if everything works, click on one of the images you uploaded (in the
bucket).
Then click on the "Object URL" - if opening it works (and you can see the
image), you configured everything as needed.
5) Update the NextJS code to use those S3 images
Now that the images are stored + served via S3, it's time to also load them
from there in your NextJS app.
As a first step, you can delete the public/images folder (so that an
empty public/ folder remains).
Now, if you also delete the .next folder in the NextJS project and you then
visit localhost:3000/meals, you should see a bunch of meals without images.
To bring them back, as a first step, edit the database data by updating
the [Link] file: Change all the image property values from image:
'/images/[Link]', to image: '[Link]' (and do that for all meals).
Alternatively, you find an updated [Link] file attached.
Next, go to the components/meals/[Link] file (which contains
the MealItem component) and update the <Image> src:
• <Image
• src={`[Link]
[Link]/${image}`}
• alt={title}
• fill
• />
Of course, use your S3 URL / bucket name!
The new src value is a string that contains the S3 URL to your bucket objects
(i.e., the URL you previously clicked for testing purposes - without the image
file name at the end). The actual image name that should be loaded is then
dynamically inserted via ${image}.
Note: This will only work if the images stored in the S3 bucket have the
names referenced in the [Link] file!
You should also update the app/meals/[mealSlug]/[Link] file and make sure
that the image on this page is also fetched from S3:
• <Image
• src={`[Link]
[Link]/${[Link]}`}
• alt={[Link]}
• fill
• />
Of course, use your S3 URL / bucket name!
Now, to reset the database data, you should delete your [Link] file (i.e.,
delete the SQLite database file) and re-run node [Link] to re-initialize it
(with the updated image values).
If you do that, and you then restart the development server ( npm run dev),
you'll notice that you now get an error when visiting the /meals page:
Error: Invalid src prop ([Link]
[Link]/[Link]) on `next/image`, hostname
"[Link]" is not
configured under images in your `[Link]`
6) Allowing S3 as an image source
You get this error because, by default, NextJS does not allow external URLs
when using the <Image> component.
You explicitly have to allow such a URL in order to get rid of this error.
That's done by editing the [Link] file:
• const nextConfig = {
• images: {
• remotePatterns: [
• {
• protocol: 'https',
• hostname: 'maxschwarzmueller-nextjs-demo-users-
[Link]',
• port: '',
• pathname: '/**',
• },
• ],
• },
• };
Of course, use your S3 URL / bucket name!
This remotePatterns config allows this specific S3 URL as a valid source for
images.
With the config file updated + saved, you should now be able to
visit /meals and see all those images again.
7) Storing uploaded images on S3
Now that we can see those dummy images again, it's finally time to also
"forward" user-generated (i.e., uploaded) images to S3.
This can be done with help of a package provided by AWS -
the @aws-sdk/client-s3 package. This package provides functionalities that
allow you to interact with S3 - e.g., to store files in a specific bucket.
Install that package via npm install @aws-sdk/client-s3.
Then, go to your lib/[Link] file and import the AWS S3 SDK (at the top of
the file):
• import { S3 } from '@aws-sdk/client-s3';
Next, initialize it by adding this line (e.g., right above the line where the db
object is created):
• const s3 = new S3({
• region: 'us-east-1'
• });
• const db = sql('[Link]'); // <- this was already there!
Almost there!
Now, edit the saveMeal() function and remove all code that was related to
storing the image on the local file system.
Instead, add this code:
• [Link]({
• Bucket: 'maxschwarzmueller-nextjs-demo-users-image',
• Key: fileName,
• Body: [Link](bufferedImage),
• ContentType: [Link],
• });
Of course, use your S3 URL / bucket name!
Also make sure to save the image filename under [Link]:
• [Link] = fileName;
The final saveMeal() function should look like this:
• export async function saveMeal(meal) {
• [Link] = slugify([Link], { lower: true });
• [Link] = xss([Link]);
•
• const extension = [Link]('.').pop();
• const fileName = `${[Link]}.${extension}`;
•
• const bufferedImage = await [Link]();
•
• [Link]({
• Bucket: 'maxschwarzmueller-nextjs-demo-users-image',
• Key: fileName,
• Body: [Link](bufferedImage),
• ContentType: [Link],
• });
•
•
• [Link] = fileName;
•
• [Link](
• `
• INSERT INTO meals
• (title, summary, instructions, creator, creator_email, image,
slug)
• VALUES (
• @title,
• @summary,
• @instructions,
• @creator,
• @creator_email,
• @image,
• @slug
• )
• `
• ).run(meal);
• }
8) Granting the NextJS backend AWS access permissions
Now, there's just one last, yet very important, step missing: Granting your
NextJS app S3 access permissions.
We did configure S3 to serve the bucket content to everyone.
But we did not (and should not!) configure it to allow everyone to write to the
bucket or change the bucket contents.
But that's what our NextJS app (via the S3 AWS SDK) now tries to do!
To grant our app appropriate permissions, you must set up AWS access keys
for your app.
This is done by adding a .[Link] file to your root NextJS project. This file
will automatically be read by NextJS and the environment variables
configured in there will be made available to the backend (!) part of your
app.
You can learn more about setting up environment variables for NextJS apps
here: [Link]
environment-variables.
In this .[Link] file, you must add two key-value pairs:
• AWS_ACCESS_KEY_ID=<your aws access key>
• AWS_SECRET_ACCESS_KEY=<your aws secret access key>
You get those access keys from inside the AWS console (in the browser). You
can get them by clicking on your account name (in the top right corner of the
AWS console) and then "Security Credentials".
Scroll down to the "Access Keys" area and create a new Access Key. Copy &
paste the values into your .[Link] file and never share these keys with
anyone! Don't commit them to Git or anything like that!
You can learn more about them
here: [Link]
[Link]
With all that done, finally, you should be able to create new meals, upload
images and see them on /meals. Even in production! Because now, the
images are stored on S3!
You find the finished, adjusted code attached to this lecture. Please note that
the .[Link] file is not included - you must add it (and use your own
credentials) if you want to run the attached code.
1. Adding Static Metadata
2. Adding Dynamic Metadata
3. Module Summary
Section 4: Pages & File-based Routing
1. From App Router To Pages Router
2. Using The Code Snapshots
3. Module Introduction
4. Our Starting Setup
5. What Is “File-based Routing”? And Why Is It Helpful?
• File-based Routing: For the files inside the folder named pages, NextJS
takes their names to be their respective paths with an exception for file
named index which it assumes to be the root path for the given folder.
1. Adding A First Page
2. Adding a Named / Static Route File
3. Working with Nested Paths & Routes
4. Adding Dynamic Path & Routes
5. Extracting Dynamic Path Segment Data (Dynamic Routes)
6. Building Nested Dynamic Routes & Paths
7. Adding Catch-All Routes
• …: It is a prefix used to catch multiple routes as a single route. It helps us
declare dynamic paths in which not only the segments are dynamic but
also the number of segments are dynamic.
1. Navigating with the “Link” Component
2. Navigating To Dynamic Routes
3. A Different Way Of Setting Link Hrefs
4. Navigating Programmatically
5. Adding a Custom 404 Page
6. Module Summary
• File-based Routing (NextJS): No extra boilerplate code required, intuitive
system, file + folder structure (in pages/folder) influences routes and
navigation works with <Link> component and imperatively
• Code-based Routing (React + react-router): Boilerpate setup in code
required (<Switch>, <Router>, …), straightforward but includes new
components + concepts, file + folder setup does not matter at all and
navigation works with <Link> component and imperatively.
1. Module Resources
Section 5: Project Time: Working with File-based Routing
1. Module Introduction
2. Planning The Project
3. Setting Up The Main Pages
4. Adding Dummy Data & Static Files
• public: Public folder is a special folder in NextJS as whatever is stored in
there is then served statically by NextJS, which means you can reference
it, be it in your HTML code or CSS code. You could easily include images
stored in your public folder because NextJS will make sure to serve any
content in the public folder as part of your overall application.
1. Adding Regular React Components
2. Adding More React Components & Connecting Components
3. Styling Components In [Link] Projects
• To use the CSS module feature of NextJs, you first have to import an
object which exposes all the CSS classes that are defined in the module
file under their respective class names. This is required because the CSS
class names contained within the module file will be transformed under
the hood by the process to make them unique for the component file.
1. <Link> & NextJS 13
Up to NextJS 13, you needed to add a nested <a> element in your <Link>s if
you wanted to add custom attributes (e.g., className) to the anchor element.
For example, the following code would be wrong (with NextJS < v13):
• <Link href="/" className="some-class">
• Click me
• </Link>
Instead, you'd have to write this code:
• <Link href="/">
• <a className="some-class">
• Click me
• </a>
• </Link>
The same solution would be required if you wanted to nest any other
elements inside your <Link>. You would need to wrap them into an extra
(potentially empty) <a> element:
• <Link href="/">
• <a>
• <span>Extra element</span>
• </a>
• </Link>
With NextJS 13 or higher, this is no longer needed, you can instead just write:
• <Link href="/" className="some-class">
• Click me
• </Link>
and
• <Link href="/">
• <span>Extra element</span>
• </Link>
The NextJS < 13 behavior will be shown in the next lecture, since that
lecture was recorded before the release of NextJS 13.
If you are watching this course with version 13 (check your [Link] file
to find out), you can ignore my solution and simplify as described above
(i.e., without the extra <a>).
1. Adding Buttons & Icons
2. Adding the “Event Detail” Page (Dynamic Route)
3. Adding a General Layout Wrapper Component
4. Working on the “All Events” Page
5. Adding a Filter Form for Filtering Events
6. Navigating to the “Filtered Events” Page Programmatically
7. Extracting Data on the Catch-All Page
8. Final Steps
9. Module Summary
10. Module Resources
Section 6: Page Pre-Rendering & Data Fetching
1. Module Introduction
2. The Problem With Traditional React Apps (and Data Fetching)
• In traditional React Apps, the actual HTML content is served by the server
and does not include any data. Now that has a couple of disadvantages.
For example, our users have to wait for the data to be loaded for them to
actually see something on the screen. Thus, the user experience could be
sub-optimal while fetching data. An even bigger problem could be SEO
though, as the crawlers will see the HTML content as served initially, i.e,
without the data and will eventually rank our web-page poorly. Though it
may not be a disadvantage for all web-applications. For example, in web-
applications in which users have to log in anyways, but this is not the
case with content-heavy applications such as a blog. The reason for
rendering data-less HTML code is because we fetch the data in our
component after the component is loaded, i.e, we fetch the data from the
client-side, we send a request to the server after our component was
rendered on the screen.
1. How NextJS Prepares & Pre-renders Pages
• Unlike React, NextJS returns a pre-rendered page, meaning that it fetches
the data on the server side itself before returning it to the client side,
which is great for SEO, but from then on, React takes over, meaning once
that page is hydrated it becomes a standard single page application, i.e,
if the page changes often, then that page is not pre-rendered but is
rendered on the client side itself using React. Now here, NextJs has two
forms of pre-rendering, i.e, Static Generation and Server Side rendering.
• Static Generation: All pages are pre-generated in advance during build
time.
• Server Side Rendering: The pages are generated just in time after
deployment when a request reaches the server.
1. Introducing Static Generation with “getStaticProps”
• getStaticProps: This function is used to tell NextJS which page is to be
pre-generated or which data is needed to pre-generate a page. This
function works only inside our page components or files that live in our
pages folder. Also, any code that you write inside of this function will not
be included in the code bundle that is sent back to your client, therefore
any code you put in there will never be seen by your clients.
1. NextJS Pre-renders By Default!
• By default, NextJS pre-renders all pages that have no dynamic data.
1. Adding “getStaticProps” To Pages
2. Running Server-side Code & Using the Filesystem
• NextJS is clever enough to strip off the server side required imports or
functions like getStaticProps from the client side bundle.
1. A Look Behind The Scenes
2. Utilizing Incremental Static Generation (ISR)
• ISR: It tells NextJS to pre-generate a page but then also re-generate it on
every request, at most every X seconds. For example, let X be 60 and you
send a request before those 60 seconds expire, you will be served the
existing page, but if you send a request after 60 seconds, you will be
served a re-generated page that will also replace the cached old page on
the server untill 60 seconds.
• revalidate: This props tells NextJS, for every incoming request to this
page it should be re-generated unless it is less than X seconds ago that it
was last generated.
1. ISR: A Look Behind The Scenes
2. A Closer Look At “getStaticProps” & Configuration Options
• notFound: If set to true, return a 404 error and therefore renders a 404
error page instead of the default page.
• redirect: It allows you to redirect the user to another page instead of the
default page.
1. Working With Dynamic Parameters
2. Introducing “getStaticPaths” For Dynamic Pages
• Currently, NextJS pre-generates all pages. In fact, it pre-generates pages
by default, but it is not the case with dynamic pages. Also, by default, the
behaviour is not to pre-generate the dynamic page because, technically,
we would not have just one page but multiple pages. Therefore, NextJS
does not know in advance how many pages it will have to pre-generate
for that dynamic page. Thus, dynamic pages are not pre-generated by
default, instead are generated just in time on the server. Therefore, we
can not use getStaticProps within dynamic pages.
1. Using “getStaticPaths”
2. “getStaticPaths” & Link Prefetching: Behind The Scenes
3. Working With Fallback Pages
• fallback: If set to false, pre-renders only the pages listed in paths while
the rest of the pages are generated just in time on the server only when
requested for.
1. Loading Paths Dynamically
2. Fallback Pages & “Not Found” Pages
• fallback: If set to true, tell NextJS that even if a path is not found we still
might be able to render a page. Therefore, we don’t have to pre-define all
possible pages or even enlist all possible values of for the dynamic
segment
1. Introducing “getServerSideProps” for Server-side Rendering (SSR)
• SSR: Required when you do have to pre-render a page for every incoming
request or you need access to the complete request object reaching the
server.
• real server-side code: It gives you a function named getServerSideProps
which you can add to a page component file which is then executed
whenever a request for this page reaches the server. Therefore, it is not
pre-generated in advance during build time, but is really code that runs
on the server only, so only after you have deployed it and which is then
re-executed for every incoming request.
1. Using “getServerSideProps” for Server-side Rendering
2. “getServerSideProps” and its Context
3. Dynamic Pages & “getServerSideProps”
4. “getServerSideProps”: Behind The Scenes
5. Introducing Client-Side Data Fetching (And When To Use It)
• We use Client Side Data Fetching with data such as data changing with
high frequency, example being stock data or highly user-specific data,
example being last orders in an online shop or even with partial data,
example being data that is only used on a part of an page. To summarise,
in scenarios where pre-fetching the data for page generation might not
work or be required. Thus, opt a more traditional approach of data-
fetching, example being useEffect with fetch.
1. Implementing Client-Side Data Fetching
2. A Note About useSWR
In the next lecture, we'll use the useSWR hook.
This hook generally still works as explained, but there is one adjustment
you'll have to make.
You must now add a default "fetcher" when working with useSWR:
• useSWR(<request-url>, (url) => fetch(url).then(res => [Link]()))
The details will be explained in the next lecture, but if you run into issues
using this hook, make the change mentioned above!
1. Using the “useSWR” NextJS Hook
2. Combining Pre-Fetching With Client-Side Fetching
3. Module Summary
4. Module Resources
Section 7: Project Time: Page Pre-rendering & Data
Fetching
1. Module Introduction
2. Preparations
3. Adding Static Site Generation (SSG) On The Home Page
4. Loading Data & Paths For Dynamic Pages
5. Optimizing Data Fetching
6. Working on the “All Events” Page
7. Using Server-side Rendering (SSR)
8. Adding Client-Side Data Fetching
9. Module Summary
10. Module Resources
Section 8: Optimizing NextJS Apps
1. Module Introduction
2. Analyzing the Need for “head” Metadata
3. Configuring the “head” Content
• Head: Allows us to add content in between the head tags in our page.
1. Adding Dynamic “head” Content
2. Reusing Logic Inside A Component
3. Working with the “_app.js” File (and Why)
4. Merging “head” Content
• NextJS automatically merges multiple head elements. Also, it
automatically resolves conflicts by taking the latest element if an element
occurs multiple times.
1. The “_document.js” File (Add What It Does)
• _app.js: It is your application shell, it may be imagined as the root
component inside of the body section of your HTML document.
• _document.js: It allows you to customize your entire HTML document. The
component within it must be a class-based component because it must
extend some component offered and provided by NextJS.
1. A Closer Look At Our Images
2. Optimizing Images with the “Next Image” Component & Feature
• Image: Optimizes the image by reducing its quality to reduce its size
without impacting the image itself, converting it to a browser friendly
type and by setting the optimized width and height of the image when
rendered for various device dimensions. NextJS optimizes images on the
fly and are stored for the future to have them already generated and
available. NextJS automatically sends new requests for the optimised
format of the image specific to that device dimension. Thus, images are
lazy loaded, unlike during build time, meaning they are only loaded when
needed and that further decreases the amount of requests we are making
in advance and the bandwidth we are taking up with our page.
Regardless of the width and height mentioned, the final styling is done
through CSS. Those parameters are there only to fetch an image of that
dimension.
1. Taking A Look At The “Next Image” Documentation
2. Module Summary
3. Module Resources
Section 9: Adding Backend Code with API Routes
(Fullstack React)
1. Module Introduction
2. What are “API Routes”?
• API: Application Programming Interface. REST (Representational State
Transfer) API is the most popular of them all. We have a web-server that
exposes certain URLs, but those URLs are not about getting requests and
sending back HTML data, but they are about accepting some data and
sending back responses with any kind of data, not necessarily HTML, but
specifically JSON (JavaScript Object Notation). They are special kinds of
URLs which you can add to your NextJS application which are not about
getting a standard browser request are sending back a pre-rendered
HTML page but which are instead about getting data, using data or
maybe even storing data in some database and sending back data in any
form of your choice.
• POST: Send request to store feedback.
• GET: Send request to get feedback.
1. Writing Our First API Route
• api: Any file within this folder is treated specially by NextJS in a way that
it does not have to send back HTML code instead it allows us to execute
any server side code, also any code that we right in those files will never
end up on client side code bundle.
1. Preparing the Frontend Form
2. Passing The Incoming Request & Executing Server-side Code
3. Sending Request To API Routes
4. Using API Requests To API Routes
5. Using API Routes For Pre-Rendering Pages
6. Creating & Using Dynamic API Routes
• .bind: Built in JavaScript method to pre-configure a function for future
execution. The first value passed to bind is the value for this keyword
inside that function, while the second value passed to bind is the value
for the first parameter received by the function.
1. Exploring Different Ways Of Structuring API Route Files
2. Module Summary
3. Module Resources
Section 10: Project Time: API Routes
1. Module Introduction
2. Starting Setup & A Challenge For You!
3. Adding a Newsletter Route
4. Adding Comments API Routes
5. Connecting the Frontend To the Comments API Routes
6. Setting Up A MongoDB Database
7. Running MongoDB Queries From Inside API Routes
8. Inserting Comments Into the Database
9. Getting Data From The Database
10. Adding Error Handling
11. More Error Handling
12. A Final Note On MongoDB Connections
In this course, we always close our MongoDB connections via [Link]().
This works and you can do that.
If you build an application where your MongoDB-related code will
execute frequently (e.g. the API route will be hit frequently), you might
want to take advantage of MongoDB's "connection pooling" though.
For this, simply remove all [Link]() calls from your code. The
connection will then NOT be closed and will be re-used across requests.
1. Module Summary
2. Improvement: Getting Comments For A Specific Event
Here's a little optional improvement you could add to the code.
At the moment, we're always fetching all (!) comments - no matter for which
event we sent a GET request.
We might just want to fetch the comments that belong to that specific event
instead.
You can adjust the code to ensure that only the comments for a specific
event (by event id) are fetched.
For this, you need to change the code in two places.
1) In helpers/[Link], add an extra, optional parameter (with a default
value) to the getAllDocuments() parameter list:
• export async function getAllDocuments(client, collection, sort)
{ ... }
becomes
• export async function getAllDocuments(client, collection, sort, filter
= {}) { ... }
The filter = {} parameter allows us to set a filter for finding documents.
The default (an empty object: {}) ensures that NO filter is applied (i.e. we
get ALL documents).
To use this filter, also change the find() method inside of
the getAllDocuments() function:
• const documents = await db
• .collection(collection)
• .find(filter) // this changed - we use the "filter" parameter!
• .sort(sort)
• .toArray();
2) In pages/api/comments/[eventId].js, pass a value for the filter argument:
Inside of the [Link] === 'GET' block, change the way you
call getAllDocuments().
• const documents = await getAllDocuments(
• client,
• 'comments',
• { _id: -1 },
• );
should become
• const documents = await getAllDocuments(
• client,
• 'comments',
• { _id: -1 },
• { eventId: eventId } // this was added!
• );
By adding these changes, you ensure that you only fetch the comments that
really belong to a specific event.
1. Module Resources
Section 11: Working with App-wide State (React Context)
1. Module Introduction
2. Our Target State & Starting Project
3. Creating a New React Context
4. Adding Context State
5. Using Context Data In Components
6. Example: Triggering & Showing Notifications
7. Example: Removing Notifications (Automatically)
8. Challenge Solution
9. Module Summary
10. Module Resources
Section 12: Complete App Example: Build a Full Blog A to
Z
1. Module Introduction