inertiajs / inertia

Inertia.js lets you quickly build modern single-page React, Vue and Svelte apps using classic server-side routing and controllers.
https://inertiajs.com
MIT License
6.52k stars 434 forks source link

Add ability to make client-side only visits #870

Open reinink opened 3 years ago

reinink commented 3 years ago

There are situations where making a visit to the server to set a prop is kind of unnecessary. For example, maybe you have a /users/create endpoint that sets a showCreateModal prop to true on the users index page.

In these situations, it would be handy if you could make a visit without hitting the server. And, it turns out you actually CAN do this today, using the Inertia.setPage() method, although it's quite ugly:

Inertia.setPage({
  component: Inertia.page.component,
  url: '/users/create',
  props: {
    ...Inertia.page.props,
    showCreateModal: true,
  },
  version: Inertia.page.version,
}, {
  replace: true,
  preserveScroll: true,
  preserveState: true
})

We could make this API nicer, by creating a dedicated method for this.

Inertia.push({
  // The page component name that will be used.
  // Optional, default: the current page component.
  component: 'Users',

  // The URL that the browser will be updated to.
  // Note, no actual request will be made.
  // Optional, default: the current URL.
  url: '/users/create',

  // The props for the page component.
  // The callback will receive the current page props.
  // Optional, default: {}
  props(props) {
    return {
      ...props,
      showCreateModal: true,
    }
  },

  // Indicates if it resets the scroll position.
  // Optional, default: true.
  preserveScroll: true,

  // Indicates if it resets the page state.
  // Optional, default: true.
  preserveState: true,
})

Which would simplify our above example to just this:

Inertia.push({
  url: '/users/create',
  props: props => ({ ...props, showCreateModal: true })
})

And we could also use the existing deprecated replace method for replacing the current history state (breaking change):

Inertia.replace({ ... })

There are also situations where you might want to make a visit to a page that uses an entirely different component:

Inertia.push({
  url: '/terms-and-conditions',
  component: 'TermsAndConditions',
})
rev4324 commented 11 months ago

It would be great to revisit this feature request. I just tried doing a fast, client-only tab navigation (all needed data is loaded on first visit) and I wasn't able to do that so Inertia router doesn't send any requests, at least with the hacky Inertia.setPage() invocation. My guess is that it now works differently. I implemented aformentioned navigation with buttons that change URL query params, but that doesn't feel right as links should be links.

tsekka commented 11 months ago

It would be great to revisit this feature request. I just tried doing a fast, client-only tab navigation (all needed data is loaded on first visit) and I wasn't able to do that so Inertia router doesn't send any requests, at least with the hacky Inertia.setPage() invocation. My guess is that it now works differently. I implemented aformentioned navigation with buttons that change URL query params, but that doesn't feel right as links should be links.

I second that. Let's say you have a simple contact modal or image lightbox, and you want to make the browser's back button to close the modal. This is easy with Vue Router, but currently, there's no way to achieve this with Inertia without making a request to the server. The setPage method is now protected, which is why even the hacky method described above doesn't work anymore.

shussel commented 10 months ago

I concur. I'm working on a setup that loads all the data to support several views and doesn't need to go back to the server unless there is a post. I have my own little router in Vue to handle this navigation, but by doing that I am essentially not using Inertia to its full potential. I also have to manually refresh certain things to deal with Inertia in those cases. Having inertia hitting the server for every act of navigation is destroys the SPA experience. If I could just use Link with an option for not hitting the server, it would solve so many problems.

joelstein commented 8 months ago

I have another use case. We have several big data pages that include all data on the initial page load and are filtered through various form controls. These settings are mirrored to the URL so users can bookmark the link and get the same options.

If we use window.history.replaceState, we compete with Inertia's use of the history state.

We got really close with the following:

// original url is "http://localhost/users"
const newUrl = "http://localhost/users?logged-in=yes&search=joel";
window.history.replaceState({...window.history.state, url: newUrl}, "", newUrl);

This almost works, but there's a brief flicker of the old URL when navigating to a new page or hitting the back button. Also, sometimes the URL params get strangely applied to the next page in the back/forward history. I think it's because Inertia is saving a copy of the state internally, or perhaps it's some other cause.

Any ideas for how we can manipulate the URL without creating conflicts with Inertia?

artygrand commented 2 months ago

Will this feature be added in v2? I'm looking forward for the release!