Learn Laravel Routing Techniques for Next.js

Learn Laravel Routing Techniques for Next.js

Published:February 16, 2023

Updated: April 5, 2023

Views: 475

nextjs
routing
fluent
laravel

Most of the projects we work on use the same backend framework: Laravel!

We love how easy it is to define routes in Laravel, and then call them from the front-end of your app.

If you're not familiar with Laravel yet, here's a simple example:

<?php

use Illuminate\Support\Facades\Route;

Route::get('/blog/{slug}', [BlogController::class, 'show'])->name('blog.show');

We've got our route set, and this is how the post routes look like:

/blog/this-is-my-first-post.

When we want to show a list of posts on the front end of our Laravel application, we can use Laravel's route helper to get the full URL—it's so convenient!

@foreach($posts as $post)
<a href="{{ route('blog.show', $post->slug) }}">
  {{ $post->title }}
</a>
@endforeach

Plus, if we ever need to change the route, all we have to do is edit it in one place and the front end will update automatically. See how easy and readable the routing is?

Routing with Next.js

Our website uses Next.js as a framework and a Headless CMS to display all the content.

With Next.js, file-based routing is used for our blog, which has the format blog/[slug].js.

Slug is a dynamic route, and using Next.js functions such as getStaticPaths and getStaticProps, we render all our blog posts in that route.

The Problem

On our Blog Index page, there is a React component that lists all the blog posts.

import Heading from '@/components/Heading';
import Layout from '@/layout/Layout';

export default function BlogIndex({ posts }) {
  return (
    <Layout title="Blog">
      <Heading>Blog</Heading>

      <div className="container py-32">
        <div className="flex flex-wrap">
          {posts.map((blog, index) => {
            return (
              <Link key={index} href={`/blog/${blog.slug}`}>
                {blog.title}
              </Link>
            );
          })}
        </div>
      </div>
    </Layout>
  );
}

To get the routing for a single blog post, we have to use template literals, as you can see here:

href={`/blog/${blog.slug}`}.

There are quite a few issues with this approach:

  • It's not easily readable and prone to typing errors.
  • If we make a typo, we have to actually visit the route for Next.js to throw a 404 error.
  • If this route is used in multiple components, we'll have to update all of those files if the route ever changes.
  • It looks pretty ugly ❌

Coming from a Laravel background, we want a simpler and cleaner approach—as we mentioned in the first example. Fortunately, there's a way to do that with just a few lines of code.

First, we can set up a routes.js file in the root folder. We can define all our dynamic routes that the front end needs.

export const routes = {
  'blog.index': {
    path: '/blog',
  },
  'blog.show': {
    path: '/blog/{slug}',
  },
  'case-studies.index': {
    path: '/case-studies',
  },
  'case-studies.show': {
    path: '/case-studies/{slug}',
  },
  'careers.index': {
    path: '/careers',
  },
  'careers.show': {
    path: '/careers/{slug}',
  },
};

Now that we have our routes.js file in place, we need a route helper that will take our route name and generate the appropriate URL along with the parameters. Have a look at the route.js helper file:

import { routes } from '../routes';

const route = (name, params = {}) => {
 
  if (! routes[name]) {
    throw new Error(
      `Route ${name} not found. Make sure you have added it to the routes.js file.`
    );
  }

  const url = routes[name];

  if (!params) {
    return url.path;
  }

  return Object.keys(params).reduce((path, key) => {
    return path.replace(`{${key}}`, params[key]);
  }, url.path);
};

export default route;

Now with our route helper in place, look at the before and after when linking to blog posts:

import route from '@/utils/route';

const Before = ({ blog }) => (
  <Link href={`/blog/${blog.slug}`}>
    {blog.title}
  </Link>
)

const After = ({ blog }) => (
  <Link href={route('blog.show', { slug: blog.slug })}>
    {blog.title}
  </Link>
)

We can make this simpler by destructuring the blog object. Here's the final BlogIndex page with the new route helper:

import Heading from '@/components/Heading';
import Layout from '@/layout/Layout';
import route from '@/utils/route';

export default function BlogIndex({ posts }) {
  return (
    <Layout title="Blog">
      <Heading>Blog</Heading>

      <div className="container py-32">
        <div className="flex flex-wrap">
          {posts.map(({ title, slug }, index) => {
            return (
              <Link key={index} href={route('blog.show', { slug })}>
                {title}
              </Link>
            );
          })}
        </div>
      </div>
    </Layout>
  );
}

Routing is much easier now that we have the route helper. It makes it easier to identify the URL and the parameter. If we need to make any changes to the route in the future, all we have to do is edit the routes.js file in the root folder - the route helper takes care of the rest.

Plus, the route helper works with multiple parameters too:

// routes.js
export const routes = {
  'blog.tags': {
    path: '/blog/{tags}/{slug}',
  },
}

// In our Category Index
route('blog.tags', {
  tags: 'react',
  slug: 'hello-world-in-react'
})

/* 
*
This will render the following url:

/blog/react/hello-world-in-react

*/

Do you have a Laravel project in mind? Learn more about our expertise in Laravel development.

Closing Thoughts

Routing with Next.js can be tricky, but with the help of the route helper, we can make it much easier to understand and maintain. Now you can now link to routes quickly and easily.

Stay up to date

Be updated with all news, products and tips we share!