Next.js: Reduce data fetching and share data between pages
ReactjsReduxFetchnext.jsSanityReactjs Problem Overview
I'm looking for solutions for better data fetching in a Next.js app. In this question I'm not just looking for a solution, I'm looking for multiple options so we can look at the pros and cons.
The problem I have
Right now I have a few pages that all include a
Reactjs Solutions
Solution 1 - Reactjs
O'right! I found this thread while I was looking for something else. But since I had to work on similar issues, I can give you some directions, and I will do my best to make it clear for you.
So there are some data which you want to have it share, across your app (pages/components).
- Next.js uses the App component to initialize pages. You can override it and control the page initialization. to achieve that simply create
_app.js
file in root ofpages
directory. For more information follow this link: https://nextjs.org/docs/advanced-features/custom-app - Just like the way you can use
getInitialProps
in your pages to fetch data from your API, you can also use the same method in_app.js
. So, I would fetch those data which I need to share them across my app and eliminate my API calls.
> Well, Now I can think of two ways to share the data across my app
- Using of
createContext
hooks.
1.1. Create a DataContext using createContext hooks. and wrap <Component {...pageProps} />
with your <DataContext.Provider>
.
Here is a code snippet to give you a better clue:
<DataContext.Provider value={{ userData, footerData, etc... }}>
<Component {...pageProps} />
</DataContext.Provider>
1.2. Now in other pages/components you can access to your DataContext like following:
const { footerData } = useContext(DataContext);
And then you are able to do the manipulation in your front-end
- populates
props
usinggetInitialProps
2.1. getInitialProps
is used to asynchronously fetch some data, which then populates props
. that would be the same case in _app.js
.
The code in your _app.js
would be something like this:
function MyApp({ Component, pageProps, footerData }) {
//do other stuffs
return (
<Component {...pageProps} footerData={footerData} />
;
}
MyApp.getInitialProps = async ({ Component, ctx }) => {
const footerRes = await fetch('http://API_URL');
const footerData = await footerRes.json();
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps, footerData };
};
2.2. Now in your pages (not in your components) you can access to props including those you have shared from _app.js
and you can start to do you manipulation.
Hope I could give you a clue and direction. Have fun exploring.
Solution 2 - Reactjs
I was looking for same few weeks ago. If you have some component which wraps all the pages,or have a component which is displayed in all pages, then here is a video which describes the same.
Here is an example, from my own project.
_app.ts
import "../styles/global.css";
import "@fontsource/rubik";
import type { AppProps } from "next/app";
import { ThemeProvider } from "next-themes";
type ComponentWithPageLayout = AppProps & {
Component: AppProps["Component"] & {
PageLayout?: React.ComponentType<any>;
};
};
const MyApp = ({ Component, pageProps }: ComponentWithPageLayout) => {
return (
<>
<ThemeProvider attribute="class">
{Component.PageLayout ? (
<Component.PageLayout>
<Component {...pageProps} />
</Component.PageLayout>
) : (
<Component {...pageProps} />
)}
</ThemeProvider>
</>
);
};
export default MyApp;
LayoutWithoutSidebar
import Navbar from "src/components/Navbar";
const LayoutWithoutSidebar = ({ children }: { children: React.ReactNode }) => {
return (
<>
<header className="sticky top-0 z-50 ">
<Navbar />
</header>
<main className="max-w-7xl m-auto">{children}</main>
</>
);
};
export default LayoutWithoutSidebar;
index.ts
import { GetStaticProps, GetStaticPropsContext, PreviewData } from "next/types";
import { ParsedUrlQuery } from "querystring";
import ApiService_ from "src/services/ApiService";
import PageHead from "src/components/PageHead";
import { Article, Project } from "src/@types/schema";
import LayoutWithoutSidebar from "src/layouts/LayoutWithoutSidebar";
import SectionSeperator from "src/components/SectionSeperator";
import IntroSection from "src/components/section/IntroSection";
import LatestSection from "src/components/section/LatestSection";
const Home = ({ latest, projects }: { latest: Article[]; projects: Project[] }) => {
return (
<div className="flex flex-col">
<PageHead title="NextJS Blog" desc="Generated by create next app" />
<IntroSection />
<SectionSeperator />
<LatestSection latest={latest} />
</div>
);
};
Home.PageLayout = LayoutWithoutSidebar;
export default Home;
export const getStaticProps: GetStaticProps = async (
context: GetStaticPropsContext<ParsedUrlQuery, PreviewData>
) => {
const _service = new ApiService_();
const latest: Article[] = await _service.getPost({
maximum: 3,
type: "Update",
});
const projects: Project[] = await _service.getProjects({});
return {
props: {
latest,
projects,
},
};
};
** Make a layout for example layout with Navbar,{children} (this is page content),Footer **
Home.PageLayout = LayoutWithoutSidebar;
here is the video from where i learned. checkout for more learn detailed explanation How to Add Nested/Persistent Layouts in Next.js