Skip to content

Once property cannot be refreshed after mutation or on redirect responses #839

@mathieutu

Description

@mathieutu

PHP package version

2.0.21

Inertia adapter(s) affected (if any)

  • React
  • Vue 3
  • Svelte
  • Not Applicable

Backend stack

laravel 12.53.0
PHP 8.5

Describe the problem

When using Inertia::once() in shared data (via HandleInertiaRequests::share()), two related problems arise that make it impossible to refresh a "once" prop after state changes.

Context

Inertia::once() is useful for sharing data that only needs to be sent once — for example, the authenticated user after login:

// HandleInertiaRequests.php
public function share(Request $request): array
{
    return [
        ...parent::share($request),
        'auth' => Inertia::once(fn () => ...)),
    ];
}

This works perfectly on the initial page load. However, both problems below make it impossible to re-deliver this prop after state changes (e.g. login, logout, profile update).

Problem : No API to invalidate or re-trigger a "once" prop

There is currently no way to tell Inertia "this once prop needs to be sent again on the next response". Once it has been sent, it is gone — even if the underlying data has changed.

This is a significant limitation for shared props that represent mutable state. If a user logs in, logs out, or updates their profile, the once prop reflecting that state becomes stale with no built-in mechanism to refresh it.

There is no equivalent of:

Inertia::refresh('auth'); // This does not exist yet

The only current workaround is to drop once entirely and use a regular shared prop, which sends the data on every request — defeating the entire purpose of once.

Problem 2: "Once" props are silently lost after a redirect when the destination component differs

When a controller mutates state and returns a redirect, once props defined in share() are never delivered to the client — and since there is no invalidation API (see Problem 1), there is no way to force them to be re-sent on the next request either.

The only mechanism doesn't work in that case, because of the way\Inertia\Response::isPartial() is done:

// vendor/inertiajs/inertia-laravel/src/Response.php:762
public function isPartial(Request $request): bool
{
    return $request->header(Header::PARTIAL_COMPONENT) === $this->component;
}

When the frontend makes a partial visit (e.g. with only: ['auth']) and the server responds with a redirect to a different component, isPartial() returns false on the follow-up request because X-Inertia-Partial-Component no longer matches the destination component. The full props are resolved — but once props have already been evaluated on the previous request and are not re-evaluated.

Concrete example: The Login form page makes a partial visit to authenticate, passing only: ['auth']. The server logs the user in and redirects to / (a Dashboard component). On the follow-up request, isPartial() returns false (correct — it's a different component), but the user once-prop is never included the request is not considered partial.

// LoginController.php
public function store(Request $request): RedirectResponse
{
    // ... authenticate user ...
    auth()->guard('web')->login($user);
    $request->session()->regenerate();

    return redirect()->intended('/'); // ← user once-prop never reaches the client
}

The frontend never receives the updated auth prop after login, leaving components that depend on it stale.

Expected behavior

  1. There should be an explicit API to invalidate/re-trigger a once prop, so that after a state mutation a controller can signal that the prop must be re-sent on the next response:
Inertia::refresh('auth');
  1. once props should survive redirect boundaries — if a once prop could not be delivered because the response was a redirect (or because the destination component differed from the requesting component), it should be included in the response to the redirect's destination.

Thanks!

Steps to reproduce

  1. Define a once shared prop in HandleInertiaRequests::share():
'auth' => Inertia::once(fn () => str_rand()),
  1. On a login page, make a partial visit using only: ['auth'] (e.g. via a <Link> component with :only="['auth']").

  2. The server authenticates the user and returns a redirect to a different page (e.g. Dashboard).

  3. Inertia follows the redirect and makes a full, non-partial request to the destination page.

Expected: auth is included in the response since it's a full request and the prop hasn't been delivered yet.

Actual: auth is absent — the once closure was already evaluated and is not re-evaluated on the follow-up request.


  1. Define the same once shared prop.
  2. Log the user in via any standard (non-partial) request.
  3. Try to force auth to be re-sent on the next response from a controller — there is no API to do so.
  4. The only workaround is removing once, causing the prop to be sent on every request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions