Data Fetching is no doubt the most important part of React App, because React is data-driven. There are three types of Data Fetching:
Static Generation means the data is fetched at build time. For Next.js versions 9.3 and up, there are two unique functions, getStaticProps and getStaticPaths, which are running at build time to generate data saved in .next/static folder by default. And then those data (HTML and JSON files) will be directly loaded when the page loads, which will certainly increase the performance. The getStaticPaths is used to specify dynamic routes, and define a list of paths that have to be rendered to HTML at build time. We don't use getStaticPaths in DeNiApps, so let's skip this for now, and focus on getStaticProps. To use it, we can simply add the function like below:
export async function getStaticProps() {
let data = null;
try {
const res = await fetch("https://api.tvmaze.com/search/shows?q=nba");
data = await res.json();
} catch (err) {
console.log(err);
}
return {
props: {
shows: data ? data.map((entry) => entry.show) : [],
},
};
}
Then the data retrieved from API will be passed to the page component as props.
Server-side Rendering means the data is fetched on each request before rendering the page. In the React's early day, somewhere in 2015, people called this Universal Rendering:
With the help of server side rendering the first rendering is never empty and performance is better.
At that time, people used ReduxAsyncConnect, later ReductConnect, and then another popular one named redial, and more. But none of them is as easy as NextJS. With NextJS, you only need to add getServerSideProps function into your pages, the function looks the same as getStaticProps. For example:
export async function getServerSideProps() {
let posts = [];
try {
const result = await getPublicPosts();
posts = result.data.data;
} catch (error) {
console.log(error);
}
return {
props: { posts: posts }
};
}
Client-side Rendering means the data is fetched after the page mounted. This is very common in React App when people don't care about Server-side Rendering. Also, in some cases, you may not be able to do Server-side, for example, when the data is only available to the user session, and the user session is saved on the client-side only, like using LocalStorage. In the Object-Oriented way, we can do the data fetching inside, ComponentDidMount, and in a functional way, since React.hook is available after 16.8, we can use useEffect, For example:
async componentDidMount() {
const ret = await getTags(this.props.accessToken);
const allTags = ret.data.data;
const tagsInputOptions = allTags.map((item) => ({
value: item.slug,
text: item.name,
key: item._id,
}));
const newAllOptions = {
...this.state.allOptions,
tags: tagsInputOptions,
};
this.setState({ allOptions: newAllOptions });
}
Or:
useEffect(() => {
fetchList();
setTimeout(() => {
setMessage("");
}, 3000);
}, []);
The parameter for getInitailProps is different depending on whether we call it in page level or in _app.js, as the example below:
//in pages/home.js
Home.getInitialProps = async ({ req }) => {
const md = new MobileDetect(req.headers["user-agent"]);
const isMobileFromSSR = !!md.mobile();
return {
isMobileFromSSR,
deviceInfo: {
mobile: md.mobile(),
tablet: md.tablet(),
os: md.os(),
userAgent: md.userAgent(),
},
};
};
//in pages/_app.js
deniApp.getInitialProps = async (appContext) => {
const agent = appContext.ctx.req
? appContext.ctx.req.headers["user-agent"]
: "";
const md = new MobileDetect(agent);
const isMobileFromSSR = !!md.mobile();
return { isMobileFromSSR };
};
As you see in page level, it's context.req, but in _app.js, it's appContex.ctr.req.