Tips for using Next.js for your next web app
This article was originally posted on Medium.com on Feb 23, 2019. Some of these tips may no longer be relevant as new versions of Next.js have come out since.
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:
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:
const 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 }
}
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;
}
return (
<div></div>
)
}
}
export default App;
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
fordata 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 }) {
const baseUrl = req ? `${req.protocol}://${req.get("Host")}` : "";
let data = await fetch(baseUrl + 'relativeURL')
return {
data: data
}
}
5. 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:
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:
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. See example for adding a Postgres index.
6. CSS breaks in prod but not development when using Material UI with Next.js
If this happens to you, try adding this line to your getPageContext.js
file:
function createPageContext() {
return {
theme,
sheetsManager: new Map(),
sheetsRegistry: new SheetsRegistry(),
//add this to fix broken css in prod
generateClassName: createGenerateClassName({
productionPrefix: "prod"
})
};
}