Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

nivv's avatar
Level 5

Eager loading data in child component using Inertia and SSR

I have a setup where I serve a normal Inertia response from a controller. All works thus far. The page component then renders different components based on the backend response, I would like to load data into these unknown.

For example I have a ContactsBlock that loads all contacts. This ContactsBlock is rendered in the genereic Page.vue component. It would be nice to let ContactsBlock have the contacts without going through the parent Page.vue. Just like one can do with View composers and blade.

Some psuedo code:

<?php

namespace App\Providers;

use App\View\Composers\ContactsComposer;
use Illuminate\Support\ServiceProvider;
use Inertia\Inertia;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Inertia::composer('Components/ContactsBlock', ContactsComposer::class);
    }
}

Page.vue

<template>
    <ContactsBlock />
</template>

<script setup>
import ContactsBlock from './ContactsBlock.vue'


</script>

ContactsBlock.vue

<template>
    <div>
        <p>All contacts</p>
        <pre>{{ contacts }}</pre>
    </div>
</template>

<script setup>

const props = defineProps({

    contacts: {
        type: Object,
        default: null,
    },
})


</script>

0 likes
8 replies
LaryAI's avatar
Level 58

To achieve eager loading of data in a child component using Inertia and SSR, you can utilize Inertia's lazy props feature. This allows you to pass data to components only when they are actually rendered, which is useful for loading data into components that are not known ahead of time.

Here's how you can modify your setup to use lazy props:

  1. In your ContactsBlock.vue component, you will need to use the usePage composable to access the lazy prop.

  2. In your controller, when you return the Inertia response, you can define a closure that will be executed only when the ContactsBlock component is rendered.

Here's an example of how you can modify your code:

// In your controller method
use Inertia\Inertia;
use Inertia\Response;

public function showPage(): Response
{
    return Inertia::render('Page', [
        // Define a closure for the 'contacts' prop
        'contacts' => fn () => Contact::all(),
    ]);
}

And in your ContactsBlock.vue component, you can access the contacts prop like this:

<template>
    <div>
        <p>All contacts</p>
        <pre>{{ contacts }}</pre>
    </div>
</template>

<script setup>
import { usePage } from '@inertiajs/inertia-vue3';

// Access the lazy prop 'contacts'
const { props } = usePage();
const contacts = props.value.contacts;
</script>

In this setup, the contacts data will only be loaded when the ContactsBlock component is actually rendered, thanks to the lazy evaluation of the closure in the Inertia response.

Please note that the usePage composable is part of the Inertia.js Vue 3 adapter, and the props.value is how you access the props passed to the page component.

Remember that for SSR to work properly with lazy props, you need to ensure that your server-side environment is set up to handle Inertia SSR. This includes having a Node.js server to render the Vue components on the server side.

nivv's avatar
Level 5

@gych I've tried that actually. But it'll only allow to include composed data in the acutal rendered component, not the "dynamic" component.

This works:

    public function boot(): void
    {
        Inertia::composer('Page/BlockPage', ContactsComposer::class);
    }

This doesn't

    public function boot(): void
    {
        Inertia::composer('Components/SomeOther/Component.vue', ContactsComposer::class);
    }
nivv's avatar
Level 5

I guess I'll have t o loop through all the block names that the page holds, and then use Inertia::share to provide the data if it's needed.

gych's avatar

@nivv Ah ok then that's indeed not going to work, not sure if I completely understand your OP.

You have a route that calls a controller method, that always returns/renders the Page component and in that return you add some data to the response which tells the front end which component like ContactBlock to render, right?

nivv's avatar
Level 5

@gych Yes, exactly. The users in the CMS can pick and choose a bunch of different blocks for every page they create.

gych's avatar
gych
Best Answer
Level 29

@nivv Ok then you could indeed use Inertia shared data, also all returned props will already be available in Inertia's usePage() helper.

nivv's avatar
Level 5

@gych Enden upp doing it like below:

<?php

namespace App\Services;

use App\Http\Integrations\Fabriq\FabriqConnector;
use App\Http\Integrations\Fabriq\Requests\GetContactsRequest;
use App\Http\Integrations\Fabriq\Requests\GetNewsRequest;
use Inertia\Inertia;

class BlockService
{
    public function __construct()
    {

    }

    const array BLOCK_MAP = [
        'ContactsBlock' => [
            'request' => GetContactsRequest::class,
            'key' => 'contacts',
            'params' => [
                'include' => 'content',
            ],
        ],
        'NewsBlock' => [
            'request' => GetNewsRequest::class,
            'key' => 'news',
            'params' => [
                'include' => 'content',
            ],
        ],
    ];

    public function parseBlocks(array $blocks)
    {
        foreach ($blocks as $block) {
            if (array_key_exists($block['block_type']['component_name'], self::BLOCK_MAP)) {
                $this->share(self::BLOCK_MAP[$block['block_type']['component_name']]);
            }
        }

        return $this;
    }

    public function share(array $block): self
    {
        $connector = new FabriqConnector();
        $request = new $block['request']($block['params']);
        $response = $connector->send($request)->throw()->json();

        Inertia::share([
            $block['key'] => $response,
        ]);

        return $this;
    }
}

Please or to participate in this conversation.