Next.js is indispensable when you want to build a high performance React app.
It’s being used to power some of my apps such as Medtally, a data-driven medical community and True Home, an automated home valuation tool for properties in Hong Kong.
Along the way, I learned a few tricks and figured out a few “gotchas” of the framework that beginners might find useful. And without further ado, let’s get started:
1. You need to cache the data from getInitialProps or the browser’s back button behavior will break.
getInitialProps
is used to fetch data for the page but it also fires when the user presses the back button on the browser. This causes the browser to scroll to the position where you previously left off but without the remote data from getInitialProps
needed to render. You can read more about this issue here.
To solve this problem, you need to cache the data on the client side after fetching it. Here’s a quick and simple way to do it:
let cache = {};
class App extends React.Component {
static async getInitialProps({ req, query, asPath, pathname }) {
let data;
//if data is in cache then use the cache
if (cache[someID]) {
data = cache[someID]
} else {
//if not, then fetch from server
data = await fetch(`someAPI`);
}
return {
data: data
}
render() {
//check if client, if so store the data in the cache.
//If you don't do this check, there will be a separate cache stored on the server since Next.js does server side rendering as well.
if (process.browser) {
cache[someID] = this.props.data;
}
render (){
//your components
}
}
}
You can also do this with Redux.
2. Use Next.js’ Link component instead of Router.push so Google can crawl your URLs
Google’s crawler doesn’t see links written like this: <div onClick={handleClickWithRouter}>Go to About Page!</div>
So avoid writing your links with Next’s Router if possible. Instead, use Next’s <Link>
component like this:
import Link from 'next/link'
function Home() {
return (
<div>
Click{' '}
<Link href="/about">
<a>here</a>
</Link>{' '}
to read more
</div>
)
}
export default Home
3. Next.js works better with Material UI React than Semantic UI React
If you’re trying to choose between Material UI and Semantic UI React component libraries to go along with your Next.js app, you should choose Material UI.
Semantic UI’s responsive components aren’t built in a way that works well with Next.js’ server-side rendering because they look for the browser’s window
object which isn’t available on the server.
If you must use Semantic UI, you can hack it together by following this GitHub ticket.
On the other hand, Material UI’s responsive components only use media queries which means your components should render in the same way on the server and in the client.
If I convinced you, head over to Material UI’s Next.js example to get started.
4. If you use isomorphic-unfetch to do your data fetching, you’ll need to provide the absolute URL
The Next.js creators recommend a library called isomorphic-unfetch
for data fetching. It has a much smaller bundle size than axios
and works well on both the client and the server.
However, isomorphic-unfetch requires an absolute URL or it will fail. I’m assuming it has something to do with the different environments (client & server) on which your code can be executed. Relative URLs are just not explicit & reliable enough in this case.
You can construct an absolute URL from getInitialProps like this:
class App extends React.Component {
static async getInitialProps({ req, query, asPath, pathname }) {
let baseUrl = req ? `${req.protocol}://${req.get("Host")}` : "";
let data = await fetch(baseUrl + 'relativeURL')
return {
data: data
}
}
- Store your URLs in the database if you want the prettiest of pretty URLs
URLs should be pretty so people want to click on them when they see them on Google.
You generally want to avoid having the database table id in your URL like this: /post/245/i-love-nextjs/
.
Ideally, your URLs should be something like this: /post/i-love-nextjs
.
But this URL is missing the id 245 needed to fetch the data from the database.
To solve this problem, you’ll need to store the URL in the database like this:
id | title | Content | url |
---|---|---|---|
245 | I love Next.js | because... | /post/i-love-nextjs |
On the server, write code to fetch data using the URL in lieu of the post id when someone requests mywebsite.com/post/i-love-nextjs. Here’s an example using Express.js:
server.get('/post/:slug', async (req, res) => {
const actualPage = "/post";
//get the data using '/post/i-love-nextjs' as the id
let data = await fetchDataWithURL(req.params.slug)
const postContent = { data: data };
app.render(req, res, actualPage, postContent);
});
I recommend slugify
if you need a library to convert text into URLs.
If you have many URLs and you’re using a relational database, you should consider adding an index to the url column so that your lookup query runs faster.
- CSS breaks in prod but not development when using Material UI with Next.js
function createPageContext() {
return {
theme,
sheetsManager: new Map(),
sheetsRegistry: new SheetsRegistry(),
//add this to fix broken css in prod
generateClassName: createGenerateClassName({
productionPrefix: "prod"
})
};
}
If this happens to you, try adding this line to your getPageContext.js file:
And that’s it!
Top comments (1)
Good article, dude. I'm new into nextJS, so this was pretty helpful.
About the last one 'createPageContext()', it should be added on my _document.js?