Latest Tutorials

Learn about the latest technologies from fellow newline community members!

  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL
  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL

Custom Annotations on XY Line Charts with visx and React

In this article, we will learn how to build an XY line chart with custom annotations using visx and React.visx is a library built and maintained by the folks at AirBnB , that provides low-level visualization primitives for React. It is a thin wrapper around D3.js and is infinitely customizable for any of your data visualization needs. visx provides React components encapsulating D3 constructs, taking away some of the complexities and learning curve involved in working with D3. In this tutorial, we will learn how to use custom annotations to enrich and add context to your line charts using visx and React. We will be charting Apple Inc.’s (AAPL) stock price over the last ten years and overlaying it with annotations for different product launch dates. This will help us understand how the stock price was affected by various important launches in the company’s history. Let us start by creating a stock standard React TypeScript app using create-react-app . We can then install the @visx/xychart library which we need for this tutorial, along with date-fns which we will use for date manipulation. In this tutorial, we will use historical stock price data for Apple (AAPL) from Kaggle. I’ve transformed the raw CSV data into JSON and simplified it to have just two main properties per data point - the x property representing the date and the y property representing the closing stock price at that date. I have also curated an additional dataset containing dates for important Apple product launches and company events in the last ten years. This has been combined with the stock price data - some of the data points have an additional events property which describes the events that occurred around the time as an array of strings. The data can be found in the GitHub repo for this tutorial . Let us use the components from the @visx/xychart library that we installed earlier to create a simple plot using the first dataset from step 2. Let us take a closer look at the different components used in the chart: When the Chart component is instantiated in App.tsx , your app should look somewhat like this: Now that we have a basic chart up and running, we can use the additional data in the events properties to add custom annotations to the chart. This can be done using the Annotation component from @visx/xychart . labelXOffset and labelYOffset are pixel values that indicate how far away the annotation needs to be from the data point it is associated with - this prevents the annotation completely overlapping and obscuring the point in question. We've filtered out the data points from stockPrices that have the events property, and added an annotation for each one that has events. Each annotation has a label that displays the date and all the events for that date. The label is attached to the data point using an AnnotationConnector . With the annotations added, your chart should now look like this: The annotations help provide a better picture of the company over the years, and can offer possible explanations for the variations in share price (do note, however, that correlation does not necessarily imply causation 😉). In this tutorial, we have used the example of Apple's share price variations to understand how to plot an XY chart with custom annotations with visx and React. There are a number of improvements that can be made to the chart, including: You can read more about the XY Chart in the official docs . As always, all the code used in this tutorial is available on GitHub .

Thumbnail Image of Tutorial Custom Annotations on XY Line Charts with visx and React

Continuous Integration (CI) with ASP.Net Core and GitHub Actions

In this article, we will learn how to set up a simple build workflow for an ASP.Net Core project with GitHub Actions.Modern apps often have large codebases with multiple teams of developers working across different geographical locations and time zones. In this scenario, it is of utmost importance to ensure that each change to the codebase works correctly not just in isolation, but in the context of all the existing code. This keeps quality levels high and guarantees the best possible experience for the app's users. Continuous Integration (CI) can be used to automatically run an array of checks on the codebase that could be triggered before code changes are merged, thus ensuring the quality of all released code. GitHub Actions is a powerful continuous integration (CI) and continuous delivery (CD) platform available for all code repositories hosted on GitHub. It allows you to build, test, and deploy your code on multiple platforms, right from your source code repository. GitHub Actions are triggered via GitHub workflows, which are YAML (either  *.yml  or  *.yaml ) files within the .github/workflows/ directory in your repository. A workflow references one or more GitHub Actions, run in a specified sequence to accomplish a given task. In the following sections, we will learn more about how GitHub Actions and workflows function, and understand how they can be used to automatically build, test, and release an ASP.Net Core project. For the purposes of this tutorial, let us use a simple .NET Core console application. We can create one using the .NET CLI which is installed along with the SDK. You can create a repository on GitHub and push the code created by the above command using the instructions in the GitHub docs . A .gitignore file can be added to ignore the build output and an optional readme file for documentation. At this stage, your GitHub repo should look somewhat like this: Now that we have our app code on GitHub, we can start creating our automated workflows. We can begin by defining a Continuous Integration(CI) workflow that will run each time code is committed to a PR branch or to main . Let us define a simple CI workflow with three steps that will install our project's NuGet dependencies, build it and run any tests, all using the dotnet CLI. We want this workflow to run on each commit to a PR branch or to main , and run on two platforms - Linux and Windows, to make sure our app works perfectly on both. As can be seen from the diagram above, each step in the workflow depends on the step before it, and can only run if the previous step is completed successfully. Now, we can create a .github/workflows directory and create a ci.yml file in there that defines this as a GitHub workflow. The YAML syntax is quite simple and readable and is easy to understand. Please refer to the comments inline in the below code block for more context. Let us now look at the structure of the workflow in detail: We've used the actions/checkout and actions/setup-dotnet predefined actions in our workflow. These, along with a wide variety of other actions are available in the GitHub Marketplace . If one isn't available for your specific purpose, you can create your own using either JavaScript or a Docker container. One of the great things about GitHub Actions is that the workflows are defined right alongside your source code. This means you can create, test, and refine new workflows on a branch before applying them to your main branch. Let us create a branch called add-ci-workflow , commit the workflow file that we have defined above in .github/workflows/ci.yml , and open a pull request to trigger the workflow. GitHub immediately recognizes the new workflow and starts the process of running the jobs defined in it. You should see status updates for each of the jobs appearing at the bottom of the pull request. You can then click through to view the details of each workflow run, where you can read through the console output from the various commands running on the build machine. This can also be accessed from the 'Actions' tab on your repository page. Once all checks have been completed, the branch can be merged into main . This will trigger a run of our workflow jobs against the newly merged code in main . A very important part of your CI setup is the idea of ensuring that only good code makes it to the main branch. To this end, GitHub allows you to set up rules that require certain GitHub Actions workflows have successfully completed before a branch can be merged. This can be used in conjunction with code reviews to keep quality levels high. The rule in the screenshot below specifies that pull requests are required for merges to main , and they can only be merged when our CI checks have succeeded. You can add a status badge for any GitHub Actions workflow in your repository to your readme file, which shows visitors and potential users of your repo the status of your CI/CD pipelines. This can be added using the URL scheme below and added as a markdown image URL in your readme: There are more parameters you can add to the URL, that are documented here . In this article, we have learned how to set up a continuous integration workflow for an ASP.NET Core app using GitHub Actions. We have also discovered how to leverage GitHub's branch protection rules with workflows to ensure only high-quality code makes it to the main branch. Most of the concepts we have explored around creating and running workflows are generic in nature, so you can apply them to any project with a different technology stack with the appropriate modifications. In an upcoming article, we will take things a step further and learn how to create releases and publish artifacts for ASP.Net Core projects with GitHub Actions workflows. All the example code used in this article is available on GitHub .

Thumbnail Image of Tutorial Continuous Integration (CI) with ASP.Net Core and GitHub Actions

I got a job offer, thanks in a big part to your teaching. They sent a test as part of the interview process, and this was a huge help to implement my own Node server.

This has been a really good investment!

Advance your career with newline Pro.

Only $30 per month for unlimited access to over 60+ books, guides and courses!

Learn More

Static Site Generation with Next.js and TypeScript (Part V) - Build Time Access Tokens and Exporting Static HTML

Disclaimer - Please read the fourth part of this blog post here before proceeding. It demonstrates how to statically generate pages with dynamic routes using the getStaticPath() function. If you just want to jump straight into this tutorial, then clone the project repository and install the dependencies. In the previous part of this tutorial series, we encountered a big problem: each getStaticProps() and getStaticPath() function required us to obtain an access token before being able to request any data from the Petfinder API. This meant that anytime we built the Next.js application for production, we had to obtain several access tokens for the Petfinder API: If we were to add more statically generated pages to the Next.js application that depend on data from the Petfinder API, then we would continue to accumulate more access tokens that are scattered throughout the Next.js application. Unfortunately, the Next.js's custom <App /> component does not support data fetching functions like getStaticProps() and getStaticPath() . This means we don't have the option of obtaining a single access token, fetching all of the necessary data (e.g., a list of pet animal types and lists of recently adopted pets) in the getStaticProps() function of the custom <App /> component and passing the data as props to every page component at build time. One way to make the access token globally available to all page components at build time is to inject it as an environment variable. Below, I'm going to show you how to build a Next.js application with a single access token. We will obtain an access token from the Petfinder API via the cURL CLI tool, set it to an environment variable named PETFINDER_ACCESS_TOKEN and execute the npm run build command with this environment variable. Then, I'm going to show you how to export the Next.js application to static HTML. This allows us to deploy and serve the Next.js application on fast, static hosting solutions like Cloudflare Pages and GitHub Pages , all without ever having to spin up a Node.js server. To get started, clone the project repository and install the dependencies. If you're coming from the fourth part of this tutorial series, then you can continue from where the fourth part left off. Within the project directory, create a Makefile : With a Makefile, we can define rules that each run a set of commands. Rules are similar, purpose-wise, to npm scripts in package.json files. Each rule consists of, at a minimum, a target and a command. The target is the name of the rule, and the command is the actual command to execute. Inside of the Makefile , add two rules: dev and build . Note : Each indentation should be a tab that's four spaces wide. Otherwise, you may encounter the error *** missing separator. Stop. . Here, invoking the make command with the dev rule as the target ( make dev ) runs npm run dev , and invoking the make command with the build rule as the target ( make build ) runs npm run build . The Makefile allows us to store the result of shell commands into variables. For example, suppose we add the following line to the top of the Makefile . In the above example, we set the variable PETFINDER_ACCESS_TOKEN to the output of the echo command, which is the string "abcdef." The shell function performs command expansion, which means taking a command as an argument, running the command and returning the command's output. Once the shell function returns the command's output, we assign this output to the simply expanded variable PETFINDER_ACCESS_TOKEN . Anytime we reference a simply expanded variable, whose value is assigned with := , the variable gets evaluated once (at the time of assignment) and procedurally, much like what you would expect in a typical, imperative programming language like JavaScript. So if we were to reference the variable's value with $() , then the value will just be the string "abcdef." ( Makefile ) GNU make comes with another "flavor" of variable, recursively expanded variable , which evaluates a variable's value completely different than what most developers are used to. It's out of the scope of this tutorial, but you can read more about them here . If you print the value of the PETFINDER_ACCESS_TOKEN environment variable in the <HomePage /> page component's getStaticProps() function, then you will see the value "abcdef" logged in the terminal when you... ( pages/index.tsx ) Note : The PETFINDER_ACCESS_TOKEN environment variable's name will not be prefixed with NEXT_PUBLIC_ . Notice that the command (along with the value of environment variables passed to it), PETFINDER_ACCESS_TOKEN=abcdef npm run dev gets logged to the terminal. To tell make to suppress this echoing , you can prepend @ to lines that you want suppressed. For simple commands like echo , you can suppress the echoing by prepending @ to the command itself, like so: However, because the command we want suppressed begins with an environment variable, we wrap the entire command in @() , like so: ( Makefile ) When you re-run the make dev command, PETFINDER_ACCESS_TOKEN=abcdef npm run dev no longer gets logged to the terminal. To obtain an access token from the Petfinder API via cURL, you must send a request to the POST https://api.petfinder.com/v2/oauth2/token endpoint with the grant type ( grant_type ), client ID ( client_id ) and client secret ( client_secret ). This data can be passed by specifying a single -d option (short for --data ) as a concatenated string of key=value pairs (delimited with an ampersand) or multiple -d options, providing a key=value pair for each one. Here's what using the single -d option looks like: And here's what using the multiple -d options looks like: Here, we will use the single -d option. When you run the cURL command, you will see that the access token is returned in stringified JSON. We can pluck the access token from this stringified JSON by piping the output of the cURL command (the stringified JSON) to a sed command. On Unix-based machines, the sed command performs many types of text processing tasks, from search to substitution. The -E option (short for the --regexp-extended option) tells the sed command to find a substring based on an extended regular expression , which requires special characters to be escaped if you want to match for them as literal characters. When you run the cURL command with the piped sed command, you will see that only the access token is returned. Within the Makefile , let's set the PETFINDER_ACCESS_TOKEN variable to the cURL command with the piped sed command, like so: To pull the NEXT_PUBLIC_PETFINDER_CLIENT_ID , NEXT_PUBLIC_PETFINDER_CLIENT_SECRET and NEXT_PUBLIC_PETFINDER_API_URL environment variables from the .env file, we can use the include directive to pause reading from the current Makefile and read from the .env file before resuming. Then, with the export directive, we can export the environment variables that were read from the .env file. ( Makefile ) When you re-run the make dev command and visit http://localhost:3000/ in a browser, you will find that the access token is immediately available to the <HomePage /> page component's getStaticProps() function. Now we can remove all instances of fetching an access token within getStaticProps() and getStaticPath() functions from the Next.js application, and pass the PETFINDER_ACCESS_TOKEN environment variable to Authorization header of any request that's sent to the Petfinder API. Also, you can now remove the console.log({ PETFINDER_ACCESS_TOKEN }) line from the <HomePage /> page component's getStaticProps() function. ( pages/index.tsx ) ( pages/types/[type].tsx ) By passing the access token as an environment variable to the Next.js application, the Next.js application now makes ten fewer requests. Like with any solution, this approach does come with a caveat. Since an access token from the Petfinder API expires one hour from the time it was issued, a caveat of this approach is that you will have to reset the development server every hour to refresh the access token. To export the Next.js application to static HTML , we must add an export npm script to the package.json file that: ( package.json ) Add a new rule named export_html to the Makefile that runs the export npm script with the PETFINDER_ACCESS_TOKEN environment variable: ( Makefile ) Note : Remember, export is already a GNU make  directive. Therefore, you cannot name the rule export . When you run the make export_html command, you will find that the Next.js application could not be exported as static HTML because it makes use of the image optimization feature, which requires a Node.js server. To resolve this problem, we need to set experimental.images.unoptimized to true in the Next.js configuration to disable the image optimization feature. Specifically, we only want to disable this feature when the NEXT_EXPORT environment variable is present. The NEXT_EXPORT environment variable will only be set when exporting the Next.js application to static HTML. ( Makefile ) ( next.config.js ) When you re-run the make export_html command, the Next.js application will be exported to static HTML. Inside the project directory, you will find the exported HTML in an out directory: To test the static pages, you can spin up a standalone HTTP server that serves the contents of the out directory: If you visit http://localhost:8080/types/horse in a browser and disable JavaScript, then you will see that this page has already been pre-rendered at build time. If you find yourself stuck at any point during this tutorial, then feel free to check out the project's repository for this part of the tutorial here . Proceed to the next part of this tutorial series to dive into building interactive, client-side features for the Next.js application. If you want to learn more advanced techniques with TypeScript, React and Next.js, then check out our Fullstack React with TypeScript Masterclass :

Thumbnail Image of Tutorial Static Site Generation with Next.js and TypeScript (Part V) - Build Time Access Tokens and Exporting Static HTML

    Static Site Generation with Next.js and TypeScript (Part II) - Fetching Data with getStaticProps

    Disclaimer - Please read the first part of this blog post here before proceeding. It provides an overview of the Next.js application that's being built throughout this tutorial series, and it introduces developers to the Next.js framework. If you just want to jump straight into this tutorial, then clone the project repository and install the dependencies. A major feature of the Next.js framework is the number of rendering strategies it supports: Each of these rendering strategies uses a different technique for data-fetching that's required for dynamically rendered content. For example, on the client-side, upon mounting a function component, you can call the useEffect hook to perform side effects. such as data-fetching, and update the UI accordingly. Alternatively, you can use a React hook library called SWR that's built specifically for data-fetching. In Next.js, data-fetching for the other browserless rendering strategies involves exporting specific functions within a page component's file: Below, I'm going to show you how to fetch data from an API with getStaticProps . To get started, clone the project repository and install the dependencies. If you're coming from first part of this tutorial series, then you can continue on from where the first part left off. Currently, the home page lacks a grid of cards that allow users to navigate to different pet animal listings. Therefore, we need to send a request to the Petfinder API to fetch a list of pet animal types. For the home page to be pre-rendered with the grid of cards, this data must be fetched within an exported getStaticProps function in pages/index.tsx . If this data is fetched from within a useEffect hook, then the home page will only be able to render the grid of cards on the client-side, not at build time. Let's export a getStaticProps function and annotate it with the GetStaticProps type, which will be imported from next . Since getStaticProps will fetch data, the function must be defined as an async function. Since data that's returned from this function gets passed as props to the page component, we need this function to return the fetched pet animal types ( types ). For now, we will return an empty array for types . ( pages/index.tsx ) To fetch any data from the Petfinder API, you must first authenticate your application and obtain an access token. Anytime data needs to be fetched from the Petfinder API, this access token must be added to the request's Authorization header. To obtain an access token, we send a POST request to https://api.petfinder.com/v2/oauth2/token . This request must be sent with the following payload: Your application's Petfinder client ID and secret should already be stored as environment variables ( NEXT_PUBLIC_PETFINDER_CLIENT_ID and NEXT_PUBLIC_PETFINDER_CLIENT_SECRET respectively). If your application does not have a Petfinder client ID and secret, then visit the Petfinder developers portal and register for a developer account. Upon sending a request to the POST /oauth2/token endpoint, a successful response should contain the following: Note : expires_in represents an expiration duration in seconds. This means that one hour after receiving the access token, the access token will expire, and you will need to obtain a new access token to continue fetching data from the Petfinder API. We will handle token expiration in a later part of this tutorial series. Let's obtain an access token within the getStaticProps function, like so: ( pages/index.tsx ) After obtaining an access token for the Petfinder API, let's send a GET request to https://api.petfinder.com/v2/types to fetch a list of pet animal types, like so: Now let's verify that the home page displays a grid of cards. Spin up the application in development mode: Within a browser, visit localhost:3000 . If you hover over the Browse Listings links, you will notice that they all point to the same route: /types . To fix this problem, we must add an id property to each pet animal type. The id property should be a unique identifier that will be used as a... Reload the page. Now the links point to the correct URLs. Let's verify that the grid is pre-rendered by Next.js at build time. Run the build script to generate an optimized version of the application that's production-ready. If you check the contents of the generated index.html file under the .next/server/pages directory, then you will notice that the grid has been pre-rendered by Next.js. You can also verify that Next.js has pre-rendered the grid by spinning up the application in production mode, which will serve the statically generated pages: If you open up the network tab of the developer tools and inspect the response for / ( index.html ), then you will notice that the page has already been pre-rendered prior to reaching the client's browser. Another problem that you might have noticed is how slow the images load since they are high resolution images directly downloaded from Unsplash. We will address this in the next part of this tutorial series. If you find yourself stuck at any point during this tutorial, then feel free to check out the project's repository for this part of the tutorial here . Proceed to the next part of this tutorial series to learn how to improve image loading with BlurHash . If you want to learn more advanced techniques with TypeScript, React and Next.js, then check out our Fullstack React with TypeScript Masterclass :

    Thumbnail Image of Tutorial Static Site Generation with Next.js and TypeScript (Part II) - Fetching Data with getStaticProps

    Static Site Generation with Next.js and TypeScript (Part IV) - Dynamic Routes with getStaticPaths

    Disclaimer - Please read the third part of this blog post here before proceeding. It walks through image optimization in a Next.js application with the <Image /> component of next/image and Blurhash, an algorithm that generates beautiful, lightweight, canvas-based placeholder images. If you just want to jump straight into this tutorial, then clone the project repository and install the dependencies. When you look at client-side routing solutions for single-page applications, such as React Router for React-based applications, you will find that they require you to define each route and manually map each one to a specific page component. With Next.js, you have a file-system based router that automatically maps each page component within the pages directory to a unique route. No extra code or routing library is needed. The route of a page is determined by the location of its page component within the pages directory. For example, if the page component <Blog /> is defined within the file pages/blog/index.tsx (or pages/blog.tsx ), then you can access it at the route /blog . The Next.js router can handle several different types of routes: If your Next.js application depends on external data to statically generate pages for dynamic routes, such as from a content management system (CMS) for blog articles, then you can export a getStaticPaths() function that specifies the paths to generate at build time, like so: Therefore, if this was placed in a pages/posts/[id].tsx file, then for each post from the JSONPlaceholder API, Next.js will pre-render a static page that can be accessed at the route /posts/:id (e.g., /posts/1 ). In the route, the named parameter id gets replaced with the value of a param with a matching name ( id: post.id ). Since the JSONPlaceholder API returns 100 posts, Next.js will pre-render 100 static pages and routes. With fallback set to false , any requests to /posts/:id outside of the range of pre-generated routes of /posts/1 to /posts/100 will return a 404 page. As for the content of the page, you will still need to export a getStaticProps() function to fetch any data that's needed to pre-render the page's content. Note : The getStaticPaths() function can be used only when the page component uses the getStaticProps() function. As for client-side navigation from one route to another, Next.js, like React Router, comes with a <Link /> component that lets users navigate to other application routes without the browser triggering a full-page reload. Below, I'm going to show you how to pre-generate paths for dynamic routes-based pages with the getStaticPaths() function. For each pet animal type, we will be adding a static page ( /types/:type ) that lists the most recently adopted pets. By the end of this tutorial, the application will gain eight more static pages, all accessible from the home page: To get started, clone the project repository and install the dependencies. If you're coming from the third part of this tutorial series, then you can continue on from where the third part left off. Within the project directory, let's install several dependencies: Since the Petfinder API returns a pet's description as stringified HTML markup, these two dependencies will help us clean up the HTML markup and prepare it so that it is safe to display to users. Let's install several dev. dependencies: According to the Petfinder API documentation , each pet returned by the API comes with photos of various sizes ( small , medium , large and full ) that are hosted on the photos.petfinder.com and dl5zpyw5k3jeb.cloudfront.net (likely subject to change in the future) domains. Therefore, we need to add the photos.petfinder.com and dl5zpyw5k3jeb.cloudfront.net domains to the list of whitelisted image domains in the Next.js configuration. In the case that the Petfinder API does not return an image for a pet, we will display a generic placeholder image, which will come from the via.placeholder.com domain. And so, we will also need to add the via.placeholder.com domain to the list of whitelisted image domains in the Next.js configuration: ( next.config.js ) First, let's create a types directory under the pages directory. Within this newly created directory, create a [type].tsx file. This file will contain a page component that will be served for the route /types/:type . The named parameter type will be replaced with slugified pet animal types, such as dog and small-furry . Within this file, let's define a page component named <TypePage /> , and export two functions, getStaticProps() and getStaticPaths() . ( pages/types/[type].tsx ) The getStaticPath() function will need to send a request to the GET /types endpoint of the Petfinder API to fetch the available pet animal types and generate a path for each one. The getStaticProps() function will need to send a request to three endpoints of the Petfinder API: And pass all of the returned data as props to the <TypePage /> component so that the component can render a list of the most recently adopted pets and a list of available breeds for the specific pet animal type. However, remember that for us to interact with the Petfinder API, we must first obtain an access token. This access token must be attached to the Authorization header of any subsequent request to the Petfinder API so that we have the necessary permissions for receiving data from the Petfinder API. The getStaticProps() function's context argument provides the values of the named parameters in the route via a params object. ( pages/types/[type].tsx ) Note : Unlike the getStaticProps() function that receives a context object as an argument, the getStaticPaths() function does not receive any argument. One thing you will notice is that if we decide to add more pages to this application, then anytime those pages require us to fetch data from the Petfinder API, we would have to obtain a new access token for each getStaticProps() / getStaticPaths() function. This is an incredibly wasteful, especially if we only need one access token to statically generate the pages at build time. Is there a way that we can obtain one access token, and use this one access token for fetching data from the Petfinder API across every getStaticProps() / getStaticPaths() function in a Next.js application? Unfortunately, Next.js's <App /> component does not support data-fetching functions like getStaticProps() (and by extension, getStaticPath() ) and getServerSideProps() , so we can't even consider obtaining an access token and passing data, such as a list of pet animal types, as props to every page component at build time. A possible solution is to leverage a Makefile that obtains an access token by using cURL , and set the access token as an environment variable so that the Next.js application can directly access the access token anywhere. We will explore this in the next part of this tutorial series. With all of the necessary data fetched from the Petfinder API, let's create two components: <AnimalCard /> and <AnimalCardsList /> . The <AnimalCard /> component will render a card that displays information about a pet, such as its name, breed, adoption status, contact information of the organization that's currently sheltering and caring for the pet, etc. The <AnimalCardsList /> component will render a list of <AnimalCard /> components in a single-column layout. Within the <TypePage /> page component, let's update the main heading with the pet type and render the <AnimalCardsList /> component under the second <section /> element. We set the animals prop of the <AnimalCardsList /> component to the list of recently adopted pets fetched from the Petfinder API ( adoptedAnimals ). ( pages/types/[type].tsx ) Now, inside of the components/AnimalCardsList.tsx file, let's define the <AnimalCardsList /> component: ( components/AnimalCardsList.tsx ) Finally, inside of the components/AnimalCard.tsx file, let's define the <AnimalCard /> component. Most of the icons used in the card come from heroicons . ( components/AnimalCard.tsx ) Let's test that everything works by spinning up the Next.js application in development mode. Inside of a browser, visit http://localhost:3000/types/horse . You will find that Next.js has successfully generated a page that belongs to the dynamic routes for /types/:type . When you generate the static pages at build time ( npm run build ), you will notice a static page for each pet animal type under the .next/server/pages/types directory. When you spin up the statically generated site in production mode ( npm run start ) and visit any of the static pages (e.g., http://localhost:3000/types/horse ), you will notice that no network requests are made to the Petfinder API and that the page has already been pre-rendered. To help with page navigation, let's add breadcrumbs to the top of the <TypePage /> component. Create a <Breadcrumbs /> component that takes a list of pages as props and renders a breadcrumb for each page. ( components/Breadcrumbs.tsx ) Then, add the <Breadcrumbs /> component to the <TypePage /> component, like so: ( pages/types/[type].tsx ) When you re-run the Next.js application, you will find the breadcrumbs at the top of the page. If you find yourself stuck at any point during this tutorial, then feel free to check out the project's repository for this part of the tutorial here . Proceed to the next part of this tutorial series to learn how to obtain a single access token at build time that can be used across every getStaticProps() / getStaticPath() function in a Next.js application. Plus, we will further flesh out the <TypePage /> component with client-side rendered content. If you want to learn more advanced techniques with TypeScript, React and Next.js, then check out our Fullstack React with TypeScript Masterclass .

    Thumbnail Image of Tutorial Static Site Generation with Next.js and TypeScript (Part IV) - Dynamic Routes with getStaticPaths