AboutContactBlogGet in touch

14 min read

Inertia 2.0: Implementing New Features in a Real-Life Project

inertia 2

The Laravel team has been on a roll lately, especially with the big reveals at Laracon US - and Inertia 2.0 is one that caught our attention this time. This latest version, introduced by Taylor Otwell, is packed with new features and improvements.

We’ve had the chance to try out these new features ourselves, and we can’t wait to share what we discovered. So, let’s take a look at how Inertia v2.0 is making SPAs more responsive, performant, and enjoyable to work with.

Inertia 2.0: What’s New?

inertia 2.0

Inertia.js has already made it simpler to build SPAs using server-side frameworks like Laravel. Traditionally, SPAs required a strict separation between frontend and backend, which added some complexity. With the new version of Inertia.js, this process becomes much easier, allowing frontend components to work seamlessly with server-rendered routes.

Now, let’s dive into the latest features and see how they perform in real-life projects.

Asynchronous Requests

Asynchronous requests in Inertia.js v2.0 allow background tasks without disrupting the main application flow. This is essential to handling tasks like getting data without causing the user interface to freeze and ensuring that users can interact with the application without any problems.

Polling for Real-Time Updates

For systems requiring updates in real-time, such as dashboards or messaging systems, polling enables regular automatic data refreshes. Polling provides automatic refreshes without having a full page reload, yet it is not as dependable as WebSockets.

Prefetching Data

Prefetching enables the app to load data in the background, usually before users request it. This reduces perceived load times and optimizes navigation by predicting user actions.

Deferred Props

Deferred props reduce the initial payload by fetching unnecessary information after the initial page loads. Because it prioritizes crucial information, this benefits apps with big datasets by speeding up the initial load.

Infinite Scrolling & Lazy Loading on Scroll

Lazy loading ensures that data only loads when needed, while infinite scrolling loads more content as users scroll. These approaches simplify managing enormous data sets, especially for pages with a lot of media.

Implementing Inertia 2.0 New Features In Real-life Project

To better demonstrate these features, let's apply Laravel and Inertia.js v2.0 to create a basic social media feed. The user experience is fast and smooth, enabling users to browse individual content, scroll through posts, and receive real-time updates.

Step 1: Initial Project Setup (Laravel 11)

  1. Install Laravel 11 and Inertia.js:

Create a new Laravel project, then install Inertia.js and Vue 3:

composer create-project laravel/laravel social-feed

cd social-feed

composer require inertiajs/inertia-laravel

npm install vue @inertiajs/inertia @inertiajs/vue3
  1. Configure Vite for Vue: Update vite.config.js to support Vue:

import { defineConfig } from 'vite';

import laravel from 'laravel-vite-plugin';

import vue from '@vitejs/plugin-vue';

export default defineConfig({

   plugins: [

       laravel({

           input: ['resources/css/app.css', 'resources/js/app.js'],

           refresh: true,

       }),

       vue(),

   ],

});

 3. Set Up app.js:

  • In resources/js/app.js, set up Inertia with Vue 3

import 'bootstrap/dist/css/bootstrap.min.css';

import { createApp, h } from 'vue';

import { createInertiaApp } from '@inertiajs/vue3';

import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';




createInertiaApp({

   resolve: name => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),

   setup({ el, App, props, plugin }) {

       createApp({ render: () => h(App, props) })

           .use(plugin)

           .mount(el);

   },

});

Step 2: Create models and Seed Data

  1. Generate Post Model and Migration:

    • Run migrations to set up a basic Post model (e.g., with title and content fields).

  2. Seed Data:

    • Use a seeder to populate the posts table with sample posts.

Async Requests

  1. Create the Feed.vue Component:

<template>

   <div class="container my-4">

       <h1 class="text-center mb-4">Social Media Feed</h1>

       <div class="text-center mb-4">

           <Link href="/about" class="btn btn-secondary">About</Link>

       </div>



       <div class="row">

           <div v-for="post in posts" :key="post.id" class="col-md-6 mb-4">

               <div class="card h-100">

                   <div class="card-body">

                       <h5 class="card-title">{{ post.title }}</h5>

                       <p class="card-text">{{ post.content }}</p>

                   </div>

               </div>

           </div>

       </div>

   </div>

</template>




<script setup>

import {Link} from '@inertiajs/vue3'



defineProps({

   posts: Array,



})

</script>
  1. Create the About.vue Component:

<template>

   <div class="container my-4">

       <h1 class="text-center mb-4">About This Social Feed</h1>

       <p class="text-center">

           This is an example page to demonstrate async navigation in Inertia.js v2.0.

       </p>

       <div class="text-center">

           <Link href="/" class="btn btn-primary">Go Back to Feed</Link>

       </div>

   </div>

</template>




<script>

import { Link } from '@inertiajs/inertia-vue3';




export default {

   components: {

       Link

   },

   name: 'About'

};

</script>

To show async navigation in Inertia 2, we place up a simple Laravel and Inertia.js application in this example. Users can interact with the application as new data loads in the background because of async navigation, which manages all page transitions and data requests non-blocking.

Polling

import { ref } from 'vue';

import { usePoll } from '@inertiajs/vue3';




export default {

   setup() {

       const visitorCount = ref(0);

       const isPolling = ref(true);




       const { stop, start } = usePoll(5000, {

           only: ['visitorCount'],

           onSuccess(response) {

               const newVisitorCount = response?.props?.visitorCount;

               if (newVisitorCount) {

                   visitorCount.value = newVisitorCount;

                   console.log("Updated visitor count:", visitorCount.value);

               } else {

                   console.log("visitorCount not found in response");

               }

           },

       }, {

           keepAlive: true,

           autoStart: true,

       });




       function togglePolling() {

           if (isPolling.value) {

               stop();

               console.log("Polling stopped");

           } else {

               start();

               console.log("Polling started");

           }

           isPolling.value = !isPolling.value;

       }




       return { visitorCount, isPolling, togglePolling };

   }

};

In this polling setup, we use Inertia’s usePoll to automatically refresh the visitor count every 5 seconds. The onSuccess callback extracts the updated visitorCount from the response and logs it. Options like only: ['visitorCount'], ensure that only the visitorCount data is fetched each time. 

Additionally, keepAlive allows polling to continue if the component becomes inactive, and autoStart initiates polling automatically. The togglePolling function enables manual control over starting and stopping polling, giving flexibility to manage polling behavior.

Lazy loading data on scroll

 

<template>
 <div class="container">
   <div class="row">
     <div class="col-12">
       <h2>Users</h2>
     </div>


     <div class="col-12">
       <ul class="list-group">
         <li v-for="user in users" :key="user.id" class="list-group-item">
           {{ user.name }}
         </li>
       </ul>
     </div>


     <WhenVisible data="top" :buffer="200">
       <template #default>
         <div class="col-12">
           <b>Top Users:</b>
           <ul class="list-group">
             <li v-for="user in top" :key="user.id" class="list-group-item">
               {{ user.name }}
             </li>
           </ul>
         </div>
       </template>


       <template #fallback>
         Loading Top Users
       </template>


     </WhenVisible>
   </div>
 </div>
</template>


<script setup>
import {WhenVisible} from '@inertiajs/vue3'


defineProps({
 users: Array,
 top: Array,
})
</script>
public function index(Request $request)
{
   return Inertia::render('User', [
       'users' => User::limit(50)->get(),
       'top' => fn() => User::inRandomOrder()->take(10)->get()
   ]);
}

In this setup, the WhenVisible component from Vue triggers data loading only when the relevant part of the page scrolls into view. Instead of preloading the "top" users list immediately, the component checks for visibility and only then makes a request to load the data. This approach reduces initial page load time by delaying non-essential data until it’s actually needed, which enhances the application's responsiveness and efficiency. By loading data on visibility, the application can better manage resources and improve user experience, especially in data-heavy environments where initial page speed is a priority.

Infinite Scrolling

public function index()
{
   $users = User::paginate(50);


   return Inertia::render('List', [
       'users' => Inertia::merge(function () use ($users) {
           sleep(2);
           return $users->items();
       }),
       'current' => $users->currentPage(),
       'last' => $users->lastPage(),
   ]);
}
<WhenVisible
     always
     :params="{
 data: {
   page: current + 1,
 },
 only: ['users', 'current'],
 preserveUrl: true,
}"
 >
     <div v-show="current < last">Loading Users</div>
     <template #fallback>
         Loading Users
     </template>
 </WhenVisible>

In this example, we implement infinite scrolling using Inertia v2 to enhance user experience by automatically loading more user data as the user scrolls down the page. The index method retrieves users with pagination, returning 50 users per page while simulating a 2-second loading delay through the Inertia::merge() function, which seamlessly integrates newly fetched data with the existing user list. 

The <WhenVisible> component detects when the user approaches the end of the currently loaded list. With the always directive, it triggers an automatic fetch for the next set of users, sending the current page plus one as a parameter. During this process, the fallback slot displays a "Loading Users" message, ensuring that users are informed while new data is being loaded.

This implementation of infinite scrolling not only improves usability by eliminating the need for manual pagination but also provides a smooth and continuous browsing experience within the application.

Prefetching

<div class="text-center">

   <Link href="/" class="btn btn-primary" prefetch="hover">Go Back to Feed</Link>

</div>

In this setup, the Link component includes the prefetch="hover" attribute, enabling Inertia to prefetch the linked page's data when the user hovers over the link. This approach allows the data to load in the background, so if the user decides to click, the page transition is almost instant. 

By reducing wait times for frequently accessed pages, this technique significantly enhances the user experience and makes the application feel faster and more responsive without requiring additional clicks or actions. Prefetching on hover is particularly useful for links to pages that users are likely to navigate to, as it proactively prepares the data before they commit to navigating.

Deferred props

ublic function authors()
{
   return Inertia::render('Author', [
       'post' => Post::latest()->first(),
       'authors' => Inertia::defer(function () {
           sleep(3); // Simulate a 3-second delay
           return Author::latest()->get();
       }),
   ]);
}
<Deferred data="authors">
   <template #fallback>
       <div class="text-center">Loading authors...</div>
   </template>
   <div class="card mt-4">
       <div class="card-body">
           <h5 class="card-title">Authors</h5>
           <ul class="list-group">
               <li v-for="author in authors" :key="author.id" class="list-group-item">
                   {{ author.name }}
               </li>
           </ul>
       </div>
   </div>
</Deferred>

 In this example, we use Inertia’s deferred props to load author data asynchronously, allowing the main page content to appear quickly while additional data loads in the background. The authors prop is marked with Inertia::defer() in the backend, which ensures that it doesn’t load immediately but instead waits 3 seconds (simulated with sleep(3)) before sending the data to the frontend.

On the frontend, we use the <Deferred> component to handle this delayed loading. The fallback slot shows "Loading authors..." while waiting for the authors data, improving the user experience by providing immediate feedback. Once the data is available, it displays each author in a list. This setup illustrates how deferred props can optimize load times, providing users with a responsive interface by loading essential content first and secondary content as it becomes available.

History Encryption

Inertia::encryptHistory();

inertia 2.0

Inertia v2 introduces History Encryption, a security feature that automatically encrypts sensitive data stored in the browser's history state. This enhancement prevents users from seeing potentially sensitive information when navigating back through their session history, such as after logging out. 

 Enabled by default, history encryption secures the session state without requiring additional configuration. By updating to Inertia 2.0, developers can ensure that their application’s data is better protected with minimal setup required. This feature is especially useful in applications where sensitive data should remain hidden in browser navigation.

Inertia 2.0: Final Thoughts

Overall, Inertia.js v2.0’s new updates make it even easier to build responsive SPAs. These new features for async handling, real-time updates, and efficient data management improve user experiences without using a fully API-driven approach. Having tested out these features ourselves, we’re excited about the possibilities they open up for even more responsive, dynamic applications.


Here’s the link to the repository.

For more detailed information, check out the official documentation of Inertia 2.0.

Meet the authors

We are a 200+ people agency and provide product design, software development, and creative growth marketing services to companies ranging from fresh startups to established enterprises. Our work has earned us 100+ international awards, partnerships with Laravel, Vue, Meta, and Google, and the title of Georgia’s agency of the year in 2019 and 2021.

Contact us