Week 1Week 3

Week 2 - Introduction to React and Next.js

~51 min read

Pre-Workshop

What's Git?

Git is a distributed version control system that tracks changes in any set of computer files, usually used for coordinating work among programmers who are collaboratively developing source code during software development.

There’s a few basic concepts to understand (for now):

  • Repositories - essentially projects
  • Commits - recorded changes/updates
  • Push Requests - sending all local commits
  • Pull Requests - receiving all online requests
  • Branches - different versions of the same project

These are VERY dumbed down explanations of how Git works, but good for just starting out. Don’t worry if you don’t understand, we’ll be using it a lot!

Make a GitHub Account

GitHub is a code hosting platform for version control and collaboration. We’ll be using it next quarter for you and your teammates to collaborate when building your client’s website. For now, we'll be using it to keep version control for the website we're making.

You can make an account here.

Confused about Git vs. GitHub? Git is a version control system that lets you manage and keep track of your code history. GitHub is a hosting service that lets you manage Git repositories. Learn more here.

Download GitHub Desktop

We'll be using GitHub Desktop, a GUI (Graphical User Interface) for our Git version control. You can download it here. You can sign in with your GitHub account.

People also use the Git CLI (Command Line Interface), but for the sake of simplicity and time, we'll be using GitHub Desktop.

What's/Downloading Node.js?

Node.js is a JavaScript Runtime Engine which is used to create server-side web applications, like the one we will be making this quarter! Make sure you download Node.js LTS here, otherwise you won't be able to compile, run, and build our project.

We need Node.js to run React.js apps locally - these types of websites must be run on a server. This is different than traditional web development where we can access the webpage files directly (index.html). Another computer/server needs to do the processing of our web application.

What does modern web development look like?

The problems with traditional web development

  • We cannot reuse things - we need to do a lot of copy/pasting, creating redundancy
  • We cannot build highly interactive user interfaces
  • We cannot maintain or create large platforms

Thankfully, people acknowledged these problems, and created tons of solutions. One we'll be looking at is called React.

What's React?

React is the library for web and native* user interfaces.

“However, if you’re building a new app or a site fully with React, we recommend using a framework.” - The React Team

It's with React that we can utilize component-driven interface development, allowing us to create components and reuse them whenever. We can code a button once, and then reuse it simply like <Button /> whenever we'd like!

What's Next.js?

"The React Framework for the Web"

Next.js is what we call a full stack React framework. It's versatile, allowing us to create React web apps of any size - from static blogs to complex dynamic applications. It's also used by some of the biggest companies in the world!

"Full Stack" refers to the combination of both front end (what we see) and back end (what we don't see).

There's a few cool features that we'll get to explore later on:

  • Automatic Image, Font, and Script Optimization
  • Advanced Routing and Nested Layouts
  • Route Handlers
  • Dynamic HTML Streaming

Next.js isn't your only option when it comes to using React to build your web app. You can use Remix, Gatsby, Expo (for native, a whole different can of worms), etc.

Getting started with Next.js

Now what you've been waiting for, actually jumping into the code! Let's get started by creating our very own Next.js project.

Make sure you are on Node.js 16.14 or later. If you just downloaded the LTS, you should be good. Otherwise, you can check by using node -v in your Terminal. If not, just download the Node.js LTS. (More information in the Pre-Workshop)

Open your Terminal and follow these steps:

  1. Navigate to the directory/folder you want to save this project in. If you want to save it in your Desktop, enter cd Desktop. If you want to save it in a GitHub folder you made in your Documents, enter cd Documents/GitHub. (Use cd to enter folders and cd ../ to back out of folders)

  2. Once you've done that, we can now create a Next.js project. Enter npx create-next-app@latest (If it asks you to install it, press ENTER/return)

  3. Now, you'll be asked some questions. Enter the text in bold. If given options, use your arrow keys and press ENTER/return. (You should be able to just keep pressing ENTER/return for steps 2-6.)

    1. What is your project named? my-website
    2. Would you like to use TypeScript? No / Yes
    3. Would you like to use Tailwind CSS? No / Yes
    4. Would you like to use src/ directory? No / Yes
    5. Would you like to use App Router? (recommended) No / Yes
    6. Would you like to customize the default import alias? No / Yes
  4. Wait for everything to finish up... If it says Success! - then congrats! You've made your first Next.js web app.

Using Version Control with our Project

Now that we have our project made, let's upload it to GitHub!

  1. Open up GitHub Desktop
  2. Click on Add Existing Repository/Add Local Repository
  3. Select your new Next.js project/folder
  4. Give the repository a name, make it public or private, and publish it!

Now, let's add our first commit!

  1. Give the commit a name of "Initial Commit"
  2. Press "Commit to main"
  3. Then, press Push origin to send the commit to GitHub.

You can batch several commits and then make a push request. In this example, we just made one commit and then pushed it.

Open up VS Code, and then open the Next.js project. You'll see the following folders and files on the left sidebar AKA the Explorer.

Here are the files and folders that are important to us (for now), you can ignore the rest.

/app

This is the /app directory, which uses Next.js's newer App Router. This folder will contain all of our pages, components, and more.

To create a page, we do the following (you don't have to do this now):

  1. Create a folder that's the name of our page. For example, create a folder named blog for the blog section of our website. The directory is /app/blog
  2. Create a file called page.js inside of the new /app/blog folder.
  3. Any of the code we edit inside of page.js will be seen on our website like so: https://website.com/blog

In traditional web development, your HTML files corresponded to webpages. https://website.com/blog would've had the file path of /blog/index.html

/public

This is the /public folder. It contains all of the files that we will be able to access directly from our website. Images or files to show on our website will go here. Keep in mind that users/visitors will also be able to access these files directly.

Everything in this folder alone can be accessed directly by anyone online, whereas other files will be parsed and compiled in the build process for our website. More on this later.

/node_modules, package-lock.json, package.json

The /node_modules folder contains all of the magic (packages and modules) that make this a Next.js project. Remember that Node.js is the underlying system behind React and Next.js.

The package-lock.json file is essentially a deep record of all the modules and packages we have installed in our project that are in /node_modules. It keeps track of dependencies, packages, sub-packages, and all of their respective versions.

The package.json file contains all of the packages we have installed - think of it as a slimmed down package-lock.json. It doesn't contain anything besides the highest level of packages we install. When we created our Next.js project, it installed all of the packages currently seen in this file.

How servers interpret this: server reads package.json, installs packages, adds the files to /node_modules and writes the information on these packages into package-lock.json.

next.config.js, tailwind.config.js

The next.config.js file is our Next.js configuration file. You can change a bit about how the framework works in here. We barely touch it.

The tailwind.config.js file is our Tailwind CSS configuration file. We’ll be able to change how Tailwind CSS works for us here, from colors to modifying styles to creating new style utilities. This will be really helpful when working with your design team to make the design system transfer smoothly. We can also download Tailwind CSS plugins and tell our system to use them.

.eslintrc.json, .gitignore, README.md

The .eslintrc.json file is our ESLint configuration file. ESLint is a static code analysis tool that checks your JavaScript code for common problems, such as syntax errors, formatting issues, code style violations, and potential bugs.

The .gitignore file controls how our git repository works! We can ignore certain files to send to GitHub, like private or personal information. We’ll go into that later too.

/node_modules and package-lock.json can get/are so big that we ignore them via this file!

The README.md file is our repository README. You can use Markdown to write whatever you want here and it’ll show up on your repository’s home page! This is commonly used for information on a repository or how to set it up.

Running our Next.js Application

Before we get into gutting a lot of the boilerplate code and adding our own, let's run our Next.js app.

  1. First, we'll need to open the Integrated Terminal in VS Code. There are a few ways to do so, but we'll just use press Terminal→New Terminal
  2. Then, run npm run dev (Make sure the directory of the Terminal is inside of your Next.js project.)
  3. Now, go to localhost:3000

And you'll see a website! If you open /app/page.js, you'll see that the code in that file is seen on the webpage! Feel free to mess with it and see it change in real time.

Did we mention Next.js has fast reload? You can now code and see results in real-time! Just another benefit.

npm run dev starts up the local development server at localhost:3000. Press the control+C keyboard shortcut in the Integrated Terminal to kill it. For now, we'll keep it running.

Gutting the Next.js project

Now, we're going to remove a lot from the project, and add a bit as well.

In /app/page.js, remove everything and replace it with:

/app/page.js
export default function Home() {
  return <p>Hello World!</p>;
}

In /app/globals.css, make sure it looks like:

/app/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;

This file is the CSS applied to every page. If you want some global CSS styles, they should go in here. For now, we just want what Tailwind CSS comes with.

In tailwind.config.js, make sure it looks like so:

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./components/**/*.{js,ts,jsx,tsx,mdx}",
    "./app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};

You can delete all the files in /public as well.

This is a great time to make a commit! Make sure you add a commit message, and then push it to GitHub.

Diving into /app

Ok great, now let's go back into /app. You'll see four files:

  • page.js
  • layout.js
  • globals.css
  • favicon.ico

layout.js

We've explained everything except layout.js. Think of this as a container around page.js. It's a purely optional file, except at the root of /app. If you open it, you'll see that there's boilerplate HTML.

/app/layout.js
import "./globals.css";
import { Inter } from "next/font/google";

const font = Inter({
  subsets: ["latin"],
});

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={`${font.className}`}>{children}</body>
    </html>
  );
}

It imports our CSS, applies a font (more on this later), and establishes the body of our webpages. Whenever you have layout.js, it passes itself down to children pages (deeper pages.)

For example, if I add a piece of HTML into /app/layout.js, it will appear on every single page in your web app automatically. But if I put HTML into /app/blog/layout.js, it won't appear on https://website.com/, only on https://website.com/blog and beyond, like https://website.com/blog/this-is-a-post.

It's a bit hard to understand, but will make more sense as we use it in the future.

Simply, pages are used to show UI unique to a route, and layouts are used to show UI that is shared across multiple routes.

These resources from Next.js are extremely helpful in understanding how this works. Try this App Router Demo to interact with a system that uses pages and layouts.

Creating a Navbar

Let's create a Navbar as the starting place for our website! Open /app/page.js, and add the following code:

/app/page.js
export default function Home() {
  return (
    <nav>
      <div>
        <a href="/">My Website</a>
        <ul>
          <li>
            <a href="/blog">Blog</a>
          </li>
          <li>
            <a href="/photos">Photos</a>
          </li>
        </ul>
      </div>
    </nav>
  );
}

If we go to localhost:3000, you'll see our navbar...just unstyled. Let's add some style to it! Using Tailwind CSS, we can add some great design with CSS classes:

/app/page.js
...
<nav className="border-b border-gray-800 sticky top-0 bg-gray-900 text-gray-100 z-10">
  <div className="h-14 max-w-7xl p-4 mx-auto flex items-center justify-between">
    <a href="/" className="font-medium text-lg md:hover:underline">
      My Website
    </a>
    <ul className="flex items-center justify-end space-x-4 text-sm font-medium">
      <li className="md:hover:underline">
        <a href="/blog">Blog</a>
      </li>
      <li className="md:hover:underline">
        <a href="/photos">Photos</a>
      </li>
    </ul>
  </div>
</nav>
...

In JSX, we have to use className instead of class so make sure you break that habit!

There's a decent amount going on, so we'll break it down.

  • <nav>
    • Apply a border to the bottom and give it a color of gray-800
    • Add sticky positioning with a top position of 0
    • Make the background the gray-900 color (Learn more about Tailwind CSS colors here)
    • Make the text the gray-100 color
    • Add a z-index of 10
  • <div>
    • Give a height of 14 (14 is 3.5rem in Tailwind CSS. Learn more here)
    • Have a max width of 7xl (7xl is 80rem in Tailwind CSS. Learn more here)
    • Give a padding of 4 on all sides (4 is 1rem in Tailwind CSS. Learn more here)
    • Put equal margin on the left and right sides (x-axis)
    • Apply flex
    • Place items vertically centered
    • Justify items horizontally between each other
  • <a>
    • Make the font weight medium
    • Make the text size large (lg is 1.125rem in Tailwind CSS. Learn more here)
    • When the screen size is md or larger, and the cursor is hovering over, show an underline. (md is 768px in Tailwind CSS. Learn more here)
  • <ul>
    • Apply flex
    • Place items vertically centered
    • Justify items horizontally at the end
    • Put space of 4 between each element (4 is 1rem in Tailwind CSS. Learn more here)
    • Make the text size small (sm is 0.875rem in Tailwind CSS. Learn more here)
    • Make the font weight medium
  • <li>
    • When the screen size is md or larger, and the cursor is hovering over, show an underline. (md is 768px in Tailwind CSS. Learn more here)

It seems like a lot, but since Tailwind CSS abstracts so much of this, you rarely think about the rems or pixels involved in the process - everything just works.

Creating a Component

Finally, let's make our very first component with this code we've made. And it's really easy!

/app/page.js
export default function Home() {
  return <Navbar />;
}

function Navbar() {
  return (
    <nav className="border-b sticky top-0 bg-gray-900 text-gray-100 border-gray-800 z-10">
      <div className="h-14 max-w-7xl p-4 mx-auto flex items-center justify-between">
        <a href="/" className="font-medium text-lg md:hover:underline">
          My Website
        </a>
        <ul className="hidden md:flex items-center justify-end space-x-4 text-sm font-medium">
          <li className="md:hover:underline">
            <a href="/blog">Blog</a>
          </li>
          <li className="md:hover:underline">
            <a href="/photos">Photos</a>
          </li>
        </ul>
      </div>
    </nav>
  );
}

This is a great time to make a commit! Make sure you add a commit message, and then push it to GitHub.

Notice how we only declared export default for the Home function, but not for the Navbar function. This is because for page.js files, we need to export the function we want to see on the webpage. There can only be one default export per file. There are some instances outside of page.js and even layout.js that we'd want multiple exports, but we'll get to that later.

All we need to do is create functions, and they become components! But what good is that? Well...

/app/page.js
export default function Home() {
  return (
    <div>
      <Navbar />
      <Navbar />
      <Navbar />
      <Navbar />
    </div>
  );
}

Now, you'll see four Navbars. No additional code needed! In HTML, we would have to duplicate the code for the Navbar itself four times!

Another cool thing is that if we update the Navbar, it updates everywhere we use it. If we change the color of the Navbar, it changes everywhere. If we add a new link, it adds it everywhere. This is the power of components.

And that's it for this Workshop. It was a bit of a doozy, but hopefully you've learned a lot. Next week, we'll dive deeper into components, adding multiple pages, and more.

Practice

Here are some options to practice this week:

  • Make your Navbar yours!
    • Using Tailwind CSS, customize the Navbar to your liking with different colors, styles, etc.
  • Make more components!
    • Now that you've made your first component, what else can you make? (and duplicate)
    • Maybe a Button component. Or a Footer component. Or whatever you want!

Like always, if you have any questions, feel free to ask and let us know!

Workshops