'Next.js: Passing data to nested routes

Issue:

Right now, I have a dynamic route that fetches data using getServerSideProps(). Within this page, there are multiple tabs that renders different data depending on state (which tab is selected).

I wish to transition from using multiple tabs on this page, to instead using nested routes. However, I am having difficulty obtaining the data originally fetched in these nested routes. Is there an efficient way of doing so, without having to call getServerSideProps() again?

My intended setup looks like this, where [page] calls getServerSideProps():

[page].jsx
|_tab1.jsx
|_tab2.jsx
|_tab3.jsx

My current [page].jsx, where I would like to use separate, nested pages that have access to these props (instead of rendering each tab based on state):

export default function Page(props) {
    const [currentTab, setCurrentTab] = useState("home");

    return (
        <div>
            <div id="tab1" onClick={() => setCurrentTab("home")}>
                home
            </div>
            <div id="tab2" onClick={() => setCurrentTab("posts")}>
                posts
            </div>
            <div id="tab3" onClick={() => setCurrentTab("info")}>
                info
            </div>

            {currentTab === "home" ? (
                <HomeTab props={props}/>
            ) : currentTab === "posts" ? (
                <PostsTab props={props}/>
            ) : (
                <InfoTab props={props}/>
            )}
        </div>
    );
}

Attempts

  • I've attempted using the context API to utilize data globally, which my other pages can use. However, this requires the user to visit the original dynamic route first.
  • Call getServerSideProps() on each nested route. Although this works, I wish to find a better solution, since I'm fetching data on each nested route while the route they're nested under has all of this data available already.


Solution 1:[1]

You can use shallow routing in next/route or next/link

Note that, in the below example, I'm using next/link for the demonstration. Without your tab data, I'd assume you have an array of tabs in data

import { useEffect } from 'react'
import Link from 'next/link'

//the path is `/tab/:tabId`
function Tab({ data }) {
  const [tabData, setTabData] = useState(data[0]) //first tab data as default for example

  useEffect(() => {
    setTabData(data[tabId])
  }, [router.query.tabId])

  return <>
     <Link href="/tab/0" shallow />
     <Link href="/tab/1" shallow />
     <div>
        {tabData}
     </div>
  </>
}

export async function getServerSideProps(context) {
  return {
    props: {
       data: [], //tabs' data you fetched from the API
    }, 
  }
}

export default Tab

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nick Vu