Integrating React and InertiaJS with TypeScript

Jose Nucamendi

José Nucamendi

27 May, 2024

Inertiajs

Welcome to this comprehensive tutorial where we will explore the powerful combination of Laravel, InertiaJS, TypeScript, and React. By the end of this guide, you'll have a solid understanding of how to build modern, robust web applications using these technologies.

Why this stack?


Laravel is a popular PHP framework known for its elegant syntax, extensive feature set, and strong community support. It simplifies the development process with tools and libraries for routing, authentication, and database management, making it an ideal choice for backend development.


InertiaJS bridges the gap between traditional server-side frameworks and modern single-page applications (SPAs). It allows you to build dynamic, single-page apps without the complexity of a fully client-side solution. InertiaJS leverages the power of server-side rendering while providing a seamless user experience.


TypeScript, a superset of JavaScript, adds static typing to your code, enabling you to catch errors early in the development process. It enhances code quality, maintainability, and scalability, making it a preferred choice for larger projects.


React is a powerful JavaScript library for building user interfaces. Its component-based architecture and efficient rendering make it perfect for creating interactive and dynamic web applications.




First, we need to create a Laravel project using:


composer create-project laravel/laravel example


Server side configuration


Install server side adapter using composer.


composer require inertiajs/inertia-laravel



In the resources/views path, we need to create the app.blade.php file and include the following content:


<!DOCTYPE html>

<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
    @vite('resources/ts/app.tsx')
    @inertiaHead
</head>

<body>
@inertia
</body>
</html>



As mentioned in the official documentation, Inertia will default to using the app.blade.php file located in the resources/views folder. However, you can change this if desired by using the Inertia::setRootView() method.

Now we will install the Inertia middleware using Composer:


php artisan inertia:middleware



Once the middleware has been published, append the HandleInertiaRequests middleware to the web middleware group in your application's bootstrap/app.php file.


<?php 

use App\Http\Middleware\HandleInertiaRequests;

$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);

...other singleton instances

$app->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [
        HandleInertiaRequests::class,
    ]);
})

return $app;


Client side configuration


First, you'll need to install the framework you'll integrate with InertiaJS. In our case, we'll use React. To do this, run the following npm command:


npm install @inertiajs/react



To avoid errors with TypeScript, you'll need to install the following dependencies:


npm install @types/react @types/react-dom typescript



Now, let's initialize our Inertia.js application. To do this, we'll create the file resources/ts/app.tsx. It's important to maintain the order of our directories so that we can work efficiently. Also in this part, we can define default layouts for certain pages.


import "../css/app.css";
import { createInertiaApp } from "@inertiajs/react";
import { createRoot } from "react-dom/client";
import React from "react";
import Layout from "./layouts/main";

createInertiaApp({
    resolve: (name) => {
        const pages = import.meta.glob("./pages/**/*.tsx", { eager: true });
        let page: any = pages[`./pages/${name}.tsx`];
        page.default.layout =
            page.default.layout || ((page: any) => <Layout children={page} />);

        return page;
    },
    setup({ el, App, props }) {
        createRoot(el).render(<App {...props} />);
    },
}).then((r) => {});



If you need to, you can change the root ID:


createInertiaApp({
  id: 'my-app',
  // ...
})



In our vite.config.js, we need to define the resources to load the application.


import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
   plugins: [

     laravel({

        input: ['resources/css/app.css', 'resources/ts/app.tsx'],

        refresh: true,

     }),

 ],
});



For the styling part, we'll be using Tailwind CSS. The app.css file should be created in resources/css.


@tailwind base;
@tailwind components;
@tailwind utilities;



Optional: You can add a Linter library to maintain order in your team.


npm install eslint prettier


Let's get started


Now we can create our app files.

First, you should create the main.tsx file in the resources/ts/layouts folder as follows:


import React from "react";

export default function Layout({ children }: { children: React.ReactNode }) {

    return (

        <main className="bg-black-base text-white">

            <div className="flex items-center justify-center">

                <div className="flex flex-col border w-full max-w-md h-screen">

                    <div className="flex-grow">{children}</div>

                    <div className="h-20 border"></div>

                </div>

            </div>

        </main>

    );
}



Then we need create the index.tsx file in the resources/ts/pages folder as follows:


import React from "react";

const Index = () => {

    const [counter, updateCounter] = useState<number>(0);
    return (<span className='m-1 p-1 bg-green text-white' onClick={() => updateCounter(prevState => prevState + 1)}>
              You have clicked this span {counter} times!
           </span>);
};

export default Index;



Now we need to create the Laravel route that will render the content of our InertiaJS application. To do this, navigate to the routes/web.php file:


Route::get('/', function () {
    return \Inertia\Inertia::render('index', []);
});



In this case, 'index' is the name of the page that we declared in the following route: resources/ts/pages/index.tsx. This approach is similar to Laravel's views, as you can also attach data collections and use them on the frontend easily without the need for asynchronous requests. You could do this from a controller if you need to. But we'll do it this way to simplify the process.


As we wrap up, I'm glad we could walk through setting up Inertia.js with React in your project. From integrating TypeScript to configuring routes and layouts, we've covered essential steps to get started. Remember, maintaining consistency with tools like ESLint and Prettier can streamline development. If you encounter any hurdles along the way, don't hesitate to reach out.


Happy coding, and may your project flourish with the power of Inertia.js and React!


References
Inertia.js. (2024). The Modern Monolith. Retrieved May 22, 2024, from InertiaJS