Home > Software design >  NextJS: what is the proper way to handle dynamic route pages?
NextJS: what is the proper way to handle dynamic route pages?

Time:08-30

I'm working on a project in NextJS for the first time, and I'm wondering what the right way to handle dynamic routing is.

I have a http://localhost:3000/trips route which displays a page with list of cards, each of which represent a "trip":

enter image description here

When I tap on one of these cards, I want to navigate to a dynamic page for that route such as http://localhost:3000/trips/0b68a50a-8377-4720-94b4-fabdabc12da1

This is my folder structure:

enter image description here

As you can see, I already have the dynamic routes set up and it is working.

TripCard is the card component. TripComponent is a grid of TripCards. trips/index.tsx contains the TripsComponent (and other UI).

Currently I'm handling the dynamic route in TripCard as:

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

And the dynamic page [tripId].tsx looks like:

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 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

I guess my question is, what is the proper way to do routing like this where I have cards, and each card will go to a dynamic URL with an associated page? In TripCard I have a hardcoded router.push:

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

But that doesn't seem like the right way to handle this. For example, what if I want to use TripCard in another view and go to another route?

What's the best way to structure code that performs this function in NextJS?

CodePudding user response:

Maybe you want to pass the url as props and use NextJs <Link/>:

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

And then use the component like this:

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

Hope this help.

CodePudding user response:

The routing you have implemented is correct only. Maybe you can try like this

For trips, you can navigate to /trips and for each trip /trip/<trip id>

If you want to make the trip URL dynamic then you can pass the URL itself to TripCard component.

url will be <route name>/<trip id>

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

CodePudding user response:

For dynamic routes, you will have to use getStaticPaths and getStaticProps to fetch the paths before and generate all the paths. When you export getStaticPaths from the page Nextjs will pre-render all the paths specified by getStaticPaths.

getStaicPaths has to return two things paths and fallback. paths property will have to be an array of params. And fallback means should Nextjs look for pages and pre-render if not pre-rendered before. Suppose after publishing the site you created a new card. So, If the fallback is true NextJs will look for the card in the database and pre-render then store it in the file system. If fallback is false it will show 404 not found.

Also Instead of using router.push use Link component.

https://nextjs.org/docs/api-reference/data-fetching/get-static-paths

  • Related