How should dynamic route pages be properly managed in NextJS?

Working on my first project using NextJS, I'm curious about the proper approach to managing dynamic routing.

I've set up a http://localhost:3000/trips route that shows a page with a list of cards representing different "trips":

https://i.stack.imgur.com/8o9td.png

When clicking on one of these cards, I want to navigate to a dynamic page for that specific trip, such as

http://localhost:3000/trips/0b68a50a-8377-4720-94b4-fabdabc12da1

This is my folder structure:

https://i.stack.imgur.com/87Cn4.png

We already have the dynamic routes set up and they are functioning properly.

The TripCard component represents each card. The TripComponent displays a grid of TripCards. trips/index.tsx contains the TripsComponent (along with other UI components).

Currently, I handle the dynamic route in TripCard as follows:

import { Trip } from './Models'
import { useRouter } from 'next/router'

const TripCard = ({ trip }: { trip: Trip }) => {
    const router = useRouter()
    return (
        <div className="card bg-base-100 shadow-xl hover:bg-gray-100 active:bg-gray-300">
            <div className="card-body" onClick={() => router.push('/trips/' + trip.id)}>
                <h2 className="card-title">{trip.name}</h2>
                <p>This is a trip!</p>
            </div>
        </div>
    )
}

export default TripCard

The dynamic page [tripId].tsx looks like this:

import { NextPage } from 'next'
import { useRouter } from 'next/router'

const TripPage: NextPage = () => {
    const router = useRouter()
    const tripId = router.query.tripId
    return (
        <div>
            <h1>This is {tripId}</h1>
        </div>
    )
}

export default TripPage

And here's TripsComponent.tsx:

import { Trip } from './Models'
import TripCard from './TripCard'

const TripsComponent = ({ trips }: { trips: Trip[] }) => {
    return (
        <div>
            <div className="grid grid-cols-4 gap-4">
                {trips.map((trip: Trip) => (
                    <div>
                        <TripCard trip={trip}></TripCard>
                    </div>
                ))}
            </div>
        </div>
    )
}

export default TripsComponent

And trips/index.tsx:

import axios from 'axios'
import { GetStaticProps, InferGetStaticPropsType, NextPage } from 'next'
import { Trip } from '../../components/Models'
import TripsComponent from '../../components/TripsComponent'

const TripsPage: NextPage = (props: InferGetStaticPropsType<typeof getStaticProps>) => {
    return (
        <div className="m-9">
            <h1 className="mt-9 text-3xl font-bold text-slate-800">Your Trips</h1>
            <div className="justify-end">
                <button className="btn btn-primary">Add Trip</button>
            </div>
            <div className="divider"></div>
            <TripsComponent trips={props.data} />
        </div>
    )
}

export const getStaticProps: GetStaticProps = async () => {
    // fetches data and passes to props
}

export default TripsPage

My concern is about the best practice for handling routing where cards lead to dynamic URLs with associated pages. Currently, in TripCard, I have a hardcoded router.push:

<div className="card-body" onClick={() => router.push('/trips/' + trip.id)}>

However, this method may not be the most efficient. For instance, what if I need to utilize TripCard in another view with a different route?

What would be the ideal way to organize code to achieve this functionality in NextJS?

Answer №1

If you're looking to pass the URL as props and utilize NextJs <Link/>, consider the following approach:

import { Trip } from './Models'
import { useRouter } from 'next/router'
import Link from 'next/link'

const TripCard = ({ trip, url }: { trip: Trip, url: string }) => {
    const router = useRouter()
    return (
        <div className="card bg-base-100 shadow-xl hover:bg-gray-100 active:bg-gray-300">
       <Link href={url} passHref>
            <div className="card-body">
                <h2 className="card-title">{trip.name}</h2>
                <p>This is a trip!</p>
            </div>
        </Link>
        </div>
    )
}

export default TripCard

To use the component, simply do:

<TripCard trip={trip} href={'/trips/' + trip.id}></TripCard>

I hope this solution works well for you.

Answer №2

When working with dynamic routes, it is important to utilize the getStaticPaths and getStaticProps functions to fetch and generate all necessary paths beforehand. By exporting getStaticPaths from the Next.js page, the platform will pre-render all specified paths.

The getStaicPaths function must return two values: paths and fallback. The paths property should consist of an array of parameters, while the fallback determines whether Next.js should search for pages to pre-render if they have not been pre-rendered before. For instance, creating a new card on a published site would trigger Next.js to look for the card in the database and pre-render it if the fallback is set to true. Otherwise, a 404 error will be displayed if the fallback is false.

Additionally, it is recommended to use the Link component instead of router.push for better navigation.

Find more information here

Answer №3

Your current routing setup is spot on. If you want to enhance it further, consider the following suggestions:

To access trips, navigate to /trips and for each individual trip, use the route /trip/<trip id>

If you wish to make the trip URL dynamic, pass the URL directly to the TripCard component.

The URL structure should be as follows:

<route name>/<trip id>

Implement this by using

 <TripCard trip={trip} url={url}></TripCard>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Connect the mileage tracker to a Datalist or grid view component

I recently downloaded the Odometer Sample from , however, I am facing an issue where only the first element in the Datalist is getting the Odometer display, while others are not displaying it. Here is the snippet of code: <script type="text/javascript" ...

Encountering a hydration issue with an SVG element embedded within a Link component in Next

I'm encountering a hydration error related to an icon within a link, Here is the error message: Error: Hydration failed because the initial UI does not match what was rendered on the server. Warning: Expected server HTML to contain a matching <svg ...

Tips for developing a module for node configuration that exclusively exports JSON data

I have a query about creating a node module that specifically exposes JSON files for configuration purposes. While I know I can easily export a JSON object from index.js, I'm exploring better alternatives to expose JSON files from the node module and ...

Creating toggling elements in Vue.js using dynamic v-show based on index and leveraging falsey v-if

What is the most effective way to use v-show for toggling elements based on their index? I have been able to toggle the elements, but when you click on the element that is already open, it does not close. <div v-for="(btn, index) in dataArray"> ...

Retrieving data for a route resolver involves sending HTTP requests, where the outcome of the second request is contingent upon the response from the first request

In my routing module, I have a resolver implemented like this: { path: 'path1', component: FirstComponent, resolve: { allOrders: DataResolver } } Within the resolve function of DataResolver, the following logic exists: re ...

Using the ternary operator in React to implement inline styles

Within my React/Typescript project, I aim to dynamically exhibit a color based on the presence or absence of a value in payload[1]. In the code snippet below, note the usage of an inline style tag. <li className="recharts-tooltip-item" style={ ...

React State not refreshing

Currently tackling a challenging e-commerce project and facing an obstacle with the following component: import React, { useEffect, useState } from 'react'; const Cart = () => { let [carts, setCarts] = useState([]); let [price, se ...

The CSS style of the Div element is not being displayed properly when embedded with JavaScript

Currently, I am working on a simple page for practice purposes. The main issue I am facing is with a div element that has a red border and a blue background. Inside the div, there is a script tag calling an external JavaScript file. Surprisingly, the JavaS ...

Select an item from the options available

Looking to automatically select a specific item from a combobox upon clicking a button on my webpage. The page includes both PHP and JavaScript code for this functionality. Currently, I have a JavaScript function triggered by the "onclick" event of the bu ...

What is the best way to modify the nested state of a dynamically generated state with the useState hook?

I'm currently facing a challenge when trying to update a nested property of a useState object. Here's the specific scenario: In the component, there is a prop "order" that contains multiple items (line_items) which represent the products in th ...

Looking to transform a PHP output value

I have a form with checkbox input, and a hidden 'sibling' input attached to it, in order to generate values of either '0' or '3' based on the checkbox status. When unchecked, the value is '0', and when checked, the ...

The Data Table experiences intermittent hanging issues (Table is empty) when sorting or loading data with Knockout binding

While working on a project, I encountered an issue with binding data to a table using Knockout JS and the JQuery/Bootstrap based; Data Table API. The problem was that the table would become unresponsive at times when sorted or loaded, without any errors be ...

Is it possible to trigger a function using an event on "Any specified selector within a provided array"?

Trying to figure out how to show/hide a group of divs with different IDs by executing a function after creating an array of IDs for the NavBar. I'm having trouble getting started, but here's what I was thinking: $.each(array1, function(i, value) ...

Trouble arises when emitting events in Vue using eventHub

In the development of my component, there arises a need to emit an event at a specific point in its lifecycle. This emitted event is intended to be listened to by another sibling component. To facilitate this communication, I am utilizing an event hub. H ...

Is it possible to authenticate a user in Firebase using Node.js without utilizing the client side?

Can I access Firebase client functions like signInWithEmailAndPassword in the Firebase SDK on the server side? Although SDKs are typically used for servers and clients use JavaScript, I need a non-JavaScript solution on the client side. I have set up the ...

Connecting Ionic 3 with Android native code: A step-by-step guide

I just finished going through the tutorial on helpstack.io and was able to successfully set up the HelpStackExample with android native based on the instructions provided in the GitHub repository. The only issue is that my company project uses Ionic 3. H ...

Redirecting www to non-www in Next.js

I've been attempting to find a viable solution by searching Google, but haven't come across anything concrete yet. My Next.js application is hosted on Vercel. During an SEO check, it identifies that my site is accessible via both www and non-www ...

How can you swap out a forward slash in vue.js?

I am facing a coding issue that I need help with: <template slot="popover"> <img :src="'img/articles/' + item.id + '_1.jpg'"> </template> Some of the numbers in my item.id contain slashes, leadin ...

Creating an Array module in Node JS

Adding a prototype to the Array class can be done in native javascript with the following code: var myArray = Array; myArray.prototype.myMethod = function(){} var testArray = new myArray(); testArray.contains(); Now I need to achieve this using a nod ...

Passing a list of objects containing lists in MVC3

Is it possible for me to send an array of objects, each containing arrays, from JavaScript to a MVC action result method? Essentially, I have a KeyValuePair with keys as arrays of strings and I need to return a list of these KeyValuePairs. In my code, I ha ...