DEV Community

Cover image for Comparing Next.js and After.js for SSR React apps
Brian Neville-O'Neill
Brian Neville-O'Neill

Posted on • Originally published at blog.logrocket.com on

Comparing Next.js and After.js for SSR React apps

Written by John-Au Yeung✏️

Next.js and After.js are both frameworks that let us build server-side-rendered React apps without the hassle of setting up SSR from scratch from a create-react-app project. In this article, we’ll compare Next.js and After.js and explore their differences.

Differences between Next.js and After.js

The major difference between Next.js and After.js is in the routing mechanism.

With Next.js, we don’t specify the routes directly; instead, we let Next.js deal with the routing automatically. It maps URLs to our components by checking the project’s file structure and mapping URLs directly to components with that. On the other hand, with After.js, we’ve to specify the routes explicitly. After.js uses React Router to do the routing.

Most of the other features like data fetching and how pages are created are pretty much the same between the two.

The way projects are created is done pretty much the same way with their own CLI programs.

LogRocket Free Trial Banner

To create a Next.js project, we run:

npm init next-app
//or
yarn create next-app
Enter fullscreen mode Exit fullscreen mode

To create an After.js project, we run:

yarn global add create-after-app
create-after-app
Enter fullscreen mode Exit fullscreen mode

Page creation

Both Next.js and After.js let us create pages by adding React components. To illustrate, we’ll create an app using the News API with Next.js and After.js. All we have to do is create components, and then it’ll display in our app.

In Next.js, if we just create the page in the pages folder, then we can navigate to it via the URL with the same name.

For instance, in Next.js, we can create index.js in the pages folder as follows:

import NavBar from '../components/navbar'
import fetch from 'isomorphic-unfetch';
import HeadTag from '../components/head-tag';

export async function getStaticProps() {
  const res = await fetch(`https://newsapi.org/v2/top-headlines/?language=en&apiKey=${process.env.apiKey}`)
  const data = await res.json()
  return {
    props: {
      data,
    },
  }
}

const Home = ({ data }) => (
  <div>
    <HeadTag />
    <NavBar />
    {data.articles.map(a => (
      <div key={a.title}>
        <h1>{a.title}</h1>
        <p>{a.description}</p>
        <p>{a.content}</p>
      </div>
    ))}
  </div>
)

export default Home
Enter fullscreen mode Exit fullscreen mode

The getStaticProps function will let us fetch data, and then we can get it from the props with the same name in our component.

We can create an about page in about.js as follows:

import NavBar from '../components/navbar'
import HeadTag from '../components/head-tag'

const Home = () => (
  <div>
    <HeadTag />
    <NavBar />
    <p>This is a news app.</p>
  </div>
)

export default Home
Enter fullscreen mode Exit fullscreen mode

Then we can navigate directly to them by going to / and /about, respectively.

In the components folder, we can create components that we can reference in the page by creating the following files:

//head-tag.js

import Head from 'next/head'

const HeadTag = () => (
  <Head>
    <title>News App</title>
  </Head>
)

export default HeadTag
Enter fullscreen mode Exit fullscreen mode
//navbar.js

import Link from 'next/link'

const NavBar = () => (
  <nav>
    <Link href="/">
      <a>Home</a>
    </Link>

    <Link href="/about">
      <a>About</a>
    </Link>
  </nav>
)

export default NavBar
Enter fullscreen mode Exit fullscreen mode

In our After.js app, we created the following components in the src folder:

//Home.js

import React, { Component } from 'react';
import NavBar from './NavBar';
import fetch from 'isomorphic-unfetch';

class Home extends Component {
  static async getInitialProps() {
    const res = await fetch(`https://newsapi.org/v2/top-headlines/?language=en&apiKey=${process.env.RAZZLE_APIKEY}`)
    const data = await res.json();
    return { data };
  }

  render() {
    const { data } = this.props;
    return (
      <div>
        <NavBar />
        {data.articles.map(a => (
          <div key={a.title}>
            <h1>{a.title}</h1>
            <p>{a.description}</p>
            <p>{a.content}</p>
          </div>
        ))}
      </div>
    );
  }
}

export default Home;
Enter fullscreen mode Exit fullscreen mode

We get the data in the initialProps static method, and then we can access it via the props.

//About.js

import React, { Component } from 'react';
import NavBar from './NavBar';

class About extends Component {
  render() {
    return (
      <div>
        <NavBar />
        <p>This is a new app</p>
      </div>
    );
  }
}

export default About;
Enter fullscreen mode Exit fullscreen mode

The components that we reference in the pages can be created in the same folder:

import React from 'react';
import { Link } from 'react-router-dom';

class NavBar extends React.Component {

  render() {
    return (
      <div>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
      </div>
    );
  }
}

export default NavBar;
Enter fullscreen mode Exit fullscreen mode

As we can see, these are all just standard components. The difference is that we used the Link component from React Router for page navigation links in After.js, and in the Next.js project, we add page navigation link with Next.js’ own Link component.

All that being said, the experience for creating pages is pretty much the same in each framework.

Routing

Routing is where Next.js and After.js are quite different.

Next.js’ routing works right out of the box without much hassle. Once we create the pages, we can navigate to them directly or with links rendered by the Link component.

On the other hand, After.js is a lot trickier. If we have a page component that has the getInitialProps method to fetch data, then we can’t add it to the routes file as an async component.

In our routes.js file, which is in the src folder of our After.js project, we have:

import React from 'react';

import { asyncComponent } from '@jaredpalmer/after';
import Home from './Home';

export default [
  {
    path: '/',
    exact: true,
    component: Home,
  },
  {
    path: '/about',
    exact: true,
    component: asyncComponent({
      loader: () => import('./About'), // required
      Placeholder: () => <div>...LOADING...</div>, // this is optional, just returns null by default
    }),
  },
];
Enter fullscreen mode Exit fullscreen mode

The About.js doesn’t fetch data before it renders, so we can include it as an async route. However, the Home component can’t be included as an async route because we have the getInitialProps async method to get data.

Routing is simply easier to deal with in a Next.js project, where it works right out of the box. Routing is more configurable with After.js, but we’ve got to configure it ourselves.

Data Fetching

Data fetching in both Next.js and After.js is done when the component is first rendered. As we can see from the previous section, index.js in our Next.js project fetches data in the async getStaticProps function. In the After.js project, we use the getInitialProps static method of the component class to fetch data before rendering the page.

In both components, the fetched data is available as props within the component.

The environment variables are stored in next.config.js in the Next.js project as follows:

module.exports = {
  env: {
    apiKey: 'your_api_key',
  },
}
Enter fullscreen mode Exit fullscreen mode

And in the After.js project, environment variables are stored in the .env file, and the keys for environment variables that we can use inside the project must be prefixed with RAZZLE_.

For example, we can write it like the following:

RAZZLE_APIKEY=your_api_key
Enter fullscreen mode Exit fullscreen mode

In both frameworks, environment variables are available as a property of the process.env object.

Conclusion

Both Next.js and After.js can be used to build server-side rendered projects. They’re useful for building server-side rendered apps without much effort.

The main difference between Next.js and After.js is the routing. Next.js maps URLs to components by their name and whether the component files are in the pages folder. In contrast, After.js uses React Router for routing, and we’ve got to configure it ourselves.


Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

Alt Text

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — start monitoring for free.


The post Comparing Next.js and After.js for SSR React apps appeared first on LogRocket Blog.

Oldest comments (0)