Using Laravel Constants in React with Inertia.js

Published on Dec 19, 2024

Consider Reading the Newer Post

This post covers using Laravel constants with React through Inertia.js effectively. However, we've now updated our approach to leverage PHP Enums for greater type safety, maintainability, and cleaner code. If you're looking for a modern alternative, check out the newer blog post that explores these enhancements in depth.


There are many ways to share data between your Laravel backend and your JavaScript frontend. Today, we’ll focus on one particularly powerful method: sharing constants between Laravel and JavaScript using Inertia.js. This approach is especially useful for managing dropdowns, form options, or validation rules, ensuring consistency and reducing repetition across your application.

By centralizing constants in Laravel, you create a single source of truth that can be used throughout your backend and frontend. In this post, we’ll walk through a practical example of defining platform constants in Laravel and using them seamlessly in a React component.

Why Use Constants?

Constants are essential for maintaining consistency, reducing errors, and improving maintainability. Defining them in Laravel allows you to:

  • Share Consistent Data Structures: Share the same data structure between your backend and frontend seamlessly.
  • Avoid Duplication: Reduce redundancy and ensure updates propagate across the application effortlessly.
  • Simplify Validation and Forms: Make validation rules and dropdown creation in your forms straightforward and error-free.

Step 1: Define the Constants in Laravel

Create a Platform class under app/Constants:

<?php

namespace App\Constants;

class Platform
{
    public const PLATFORMS = [
        'steam' => 'Steam',
        'psn' => 'PlayStation Network',
        'xbox' => 'Xbox',
        'kakao' => 'Kakao',
        'stadia' => 'Stadia',
    ];

    public static function getPlatforms(): array
    {
        // Transform into a key-value array suitable for frontend use
        return collect(self::PLATFORMS)
            ->map(function ($label, $key) {
                return [
                    'value' => $key,
                    'label' => $label,
                ];
            })
            ->values()
            ->toArray();
    }
}

How It Works

In this example, the Platform class defines a centralized list of platforms and formats them.

Using Laravel Collections to Format the Data

The getPlatforms() method in the Platform class leverages Laravel Collections to format the PLATFORMS data into a reusable structure. Let’s break down how this works:

Wrap the Data in a Collection

The collect() function takes the PLATFORMS constant and wraps it in a Laravel collection. This allows for easy manipulation of the data.

collect(self::PLATFORMS)

Transform the Data

The map() method iterates over each platform key-value pair and transforms it into an array with the following structure:

value: The platform's key (e.g., steam, psn).
label: The platform's human-readable name (e.g., Steam, PlayStation Network).

->map(function ($label, $key) {
    return [
        'value' => $key,
        'label' => $label,
    ];
})

Flatten the Structure

The values() method resets the array keys to ensure a clean, sequentially indexed array.

->values()

Convert to Plain Array

Finally, the toArray() method converts the collection into a plain PHP array, ready to be passed to the frontend.

->toArray();

What getPlatforms() Produces...

The final output of getPlatforms() is a structured array like this:

[
    ['value' => 'steam', 'label' => 'Steam'],
    ['value' => 'psn', 'label' => 'PlayStation Network'],
    ['value' => 'xbox', 'label' => 'Xbox'],
    ['value' => 'kakao', 'label' => 'Kakao'],
    ['value' => 'stadia', 'label' => 'Stadia'],
]

Step 2: Pass the Constants to the Frontend Using Inertia

In your web.php file, pass the platforms to the React component:

use App\Constants\Platform;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;

Route::get('/', function () {
    return Inertia::render('Home', [
        'platforms' => Platform::getPlatforms(),
    ]);
})->name('home');

Step 3: Use the Constants in Your React Component

In this step, we make use of the usePage hook provided by Inertia.js to access the constants passed from Laravel. The usePage hook is a powerful utility that allows you to directly access the page’s props in your React component. These props are passed down from your Laravel backend via Inertia when rendering the page.

For more details, check out the official documentation on shared data with Inertia.

Here’s how usePage is useful in this scenario:

Seamless Data Sharing:
The usePage hook enables seamless sharing of data between the backend and frontend without the need for additional API calls. In our case, the platforms constant is passed as a prop from Laravel, and we access it directly in the React component using usePage.
Centralized State Management:
Since usePage provides access to all props sent with the current Inertia response, it serves as a centralized way to manage and access state or configuration data required for a specific page.
Dynamic and Flexible:
With usePage, any data passed from Laravel, such as the platforms list, is dynamically available in the React component. This flexibility ensures that updates to the backend logic (e.g., enabling/disabling platforms) are automatically reflected in the frontend.

import React from "react";
import { Head, useForm, usePage } from "@inertiajs/react";

export default function Home() {
    // Access platforms from the page props
    const { platforms } = usePage().props;

    // Form state using Inertia's useForm hook
    const { data, setData, post, processing, errors } = useForm({
        username: "", // Input for the username
        platform: platforms?.[0]?.value || "steam", // Default to the first platform
    });

    // Handle form submission
    const handleSubmit = (e) => {
        e.preventDefault();
        post(route("search"));
    };

    return (
        <>
            <Head title="Platform Selector" />
            <div className="min-h-screen bg-gray-100 flex items-center justify-center">
                <div className="w-full max-w-md bg-white shadow rounded p-6">
                    <h1 className="text-2xl font-bold mb-4">Select Your Platform</h1>
                    <form onSubmit={handleSubmit}>
                        {/* Platform Dropdown */}
                        <select
                            className="w-full p-2 border border-gray-300 rounded mb-4"
                            value={data.platform}
                            onChange={(e) => setData("platform", e.target.value)}
                        >
                            {platforms.map((platform) => (
                                <option key={platform.value} value={platform.value}>
                                    {platform.label}
                                </option>
                            ))}
                        </select>
                        {errors.platform && (
                            <div className="text-red-500 text-sm">{errors.platform}</div>
                        )}

                        {/* Username Input */}
                        <input
                            type="text"
                            placeholder="Enter Username"
                            className="w-full p-2 border border-gray-300 rounded mb-4"
                            value={data.username}
                            onChange={(e) => setData("username", e.target.value)}
                        />
                        {errors.username && (
                            <div className="text-red-500 text-sm">{errors.username}</div>
                        )}

                        {/* Submit Button */}
                        <button
                            type="submit"
                            className="w-full bg-blue-500 text-white p-2 rounded"
                            disabled={processing}
                        >
                            {processing ? "Submitting..." : "Submit"}
                        </button>
                    </form>
                </div>
            </div>
        </>
    );
}

Step 4: Reuse Constants Anywhere

Want to use these platforms elsewhere, like in validation? The Platform constant is ready to go:

use App\Constants\Platform;
use Illuminate\Http\Request;

Route::post('/search', function (Request $request) {
    $request->validate([
        'username' => 'required|string|max:255',
        'platform' => 'required|in:' . implode(',', array_keys(Platform::PLATFORMS)),
    ]);

    // Handle the search logic here
    return response()->json(['message' => 'Search successful']);
})->name('search');

Conclusion

By centralizing your constants in Laravel and using Inertia.js, you can easily share data between your backend and frontend:

  • Write Once: Define your constants in Laravel.
  • Reuse Everywhere: Use them in React, validation, or other backend logic.
  • Keep it Simple: Laravel and Inertia make the data flow seamless.

This approach ensures consistency and makes your codebase easier to maintain. Happy coding! 👋