Shadee Merhi
Shadee Merhi

Reputation: 333

Data-fetching with React Server Components: is this a correct implementation?

I'm using Next.JS in an application where I have a Navbar component that is needed on all pages of the application, and the Navbar renders data (specifically product-categories) that must be fetched from my database.

I want this component to be server-side rendered, but since Next.JS only supports page-level SSR and not component-level SSR, it seems that I must use getServerSideProps on all pages that I want to display this Navbar and write the same API request in each one, resulting in a ton of repeated logic and API calls across several pages.

While researching how to solve this, I came across React Server Components and wonder if that would be a valid solution for this scenario, but since I'm new to the concept, I'm not sure if I understand it correctly, hence why I'm writing this question.

I'm thinking of doing the following and want to get some feedback as to whether I am on the right track.

My Navbar component would be something like as follows:

const Navbar = () => {
  const [data, setData] = useState();

  useEffect(() => {
    fetchData();
  }, []);

  const fetchData = async () => {
    const data = await fetch("/api/someEndpoint");
    setData(data);
  };

  return (
    <div>
      {data.someProperty}
      {data.someOtherProperty}
    </div>
  );
};
export default Navbar;

Then I can create a global Layout component so that the Navbar is included in all pages, which is where React.Suspense would be used (if I understand it correctly):

const Layout = ({ children }) => {
  return (
    <>
       <React.Suspense fallback={<FallbackComponent />}>
         <Navbar />
       <React.Suspense />
       {children}
    </>
  );
};
export default Layout;

Then in _app.tsx, I would include my Layout component so that the Navbar is present everywhere:

function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
  return (
      <Layout>
        <Component {...pageProps} />
      </Layout>
  );
}

So here is my question: is this a correct implementation and valid use-case of React.Suspense? Is component-level data fetching one of the proposed benefits of React Server Components?

Upvotes: 1

Views: 2581

Answers (2)

Ala Ben Aicha
Ala Ben Aicha

Reputation: 1276

Now with the Next.JS 13 version, you can create an app directory that uses react server components by default.

But you should keep in mind that most of the React hooks like useState and useEffect won't work on server components, also previous Next.js APIs such as getServerSideProps, getStaticProps, and getInitialProps are not supported in the new app directory.

So instead, you can use the new fetch() API that was built on top of the native fetch() Web API. Check the docs for more details.

Upvotes: 1

Arca Ege Cengiz
Arca Ege Cengiz

Reputation: 333

Instead of fetching via an API, you could instead use SSR in _app.tsx that would pass the data as props to the MyApp hook. Then the data could be passed down further into the Layout component, which would again pass it down even further to the Navbar component. So it would look like something along the lines of this:

// _app.tsx
function MyApp({ /* Props */, data }) {
  return (
      <Layout data={data}>
        <Component {...pageProps} />
      </Layout>
  );
}

export function getServerSideProps(context) {
  // Get data
  return {
      props: {
          data: data
      },
  }
}
// Layout.tsx
const Layout = ({ children, data }) => {
  return (
    <>
       <Navbar data={data} />
       {children}
    </>
  );
};
export default Layout;
// Navbar.tsx
const Navbar = ({ data }) => {
  return (
    <div>
      {data.someProperty}
      {data.someOtherProperty}
    </div>
  );
};
export default Navbar;

EDIT: SSR in _app.tsx doesn't work, but I found an answer here: https://stackoverflow.com/a/72325973/12190941

EDIT 2: You can use getInitalProps in _app.js if you want your entire site to be server side rendered. Do keep in mind that this will increase initial load times. I found this example in the Next.js docs here

// _app.js

// ...

MyApp.getInitialProps = async (appContext) => {
   // calls page's `getInitialProps` and fills `appProps.pageProps`
   const appProps = await App.getInitialProps(appContext);

   return { ...appProps }

Upvotes: 0

Related Questions