Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a way for a form submit to do normal data diffing on the redirect. #175

Closed
ryanflorence opened this issue May 18, 2021 · 10 comments
Closed

Comments

@ryanflorence
Copy link
Member

Some forms don't mutate data, or don't mutate data above themselves, so it's a waste to go call the loaders for layouts above it on the redirect (like our newsletter signup, checkout flow, etc.)

Maybe a boolean prop?

<Form reloadParents={false} />

Or enum?

<Form mutates="all | self" />

Default will remain to reload all routes on the redirect.

@sergiodxa
Copy link
Member

An enum would be better than a boolean, it would allow more options in the future too, something like:

<Form revalidate="none" /> <- no refetch (I'm editing something I'm not using on the screen)
<Form revalidate="self" /> <- refetch only the page of the form (useful if I know the parent doesn't have anything related to this data, e.g. my only parent is the root and I want to avoid it)
<Form revalidate="parents" /> <- refetch parent loaders (avoid self, useful if you are using an edit modal as route and you are going to close it anyway)
<Form revalidate="all" /> <- refetch all active routes on the page (default)

@ryanflorence
Copy link
Member Author

ryanflorence commented May 18, 2021

Great ideas. I just realized "self" is a little confusing, since you can redirect to a different page.

  • at /projects/new
  • post to self
  • action redirects to /projects/123
  • Don't care to reload the parent routes, but you do want to load projects/123 ofc

That's not "self" that's "leaf" or maybe "changed" which could mean "anything that wasn't here before"

I think that means all you need is "all" | "changed".

  • "all" - reload everything (I mutated parent data)
  • "changed" - I didn't mutate parent data, but ofc we need the data for anything that's new

(side note, I like "revalidate" but it makes me nervous since "form validation" is a thing and makes it ambiguous, easy to bike shed though)

@tchak
Copy link

tchak commented May 18, 2021

Maybe not exactly related but one use case I still struggle with is root-level data. In my current app, I am returning some basic config for the app that I do not expect to change very often – current locale, current translation, ENV that I want to expose to the window. On some advice from @mjackson I am setting a pretty aggressive caching in the loader and it works pretty well and maybe it is enough. But what if at some point I do want to change the locale? I am not sure yet what would be my preferred solution. Maybe some concept of base data that is loaded once but can be explicitly invalidated later?

@ryanflorence
Copy link
Member Author

ryanflorence commented May 18, 2021

@tchak it's a common enough case that maybe we have three:

  • "all" (default, includes root)
  • "all-but-root" (needs a better name, or not!)
  • "changed"

Another idea, that I don't love (but it gives you total control) is you could provide route IDs to include in the next transition:

// would exclude root
<Form revalidate={["routes/projects", "routes/projects/$id"]} />

So we have an overloaded prop where you can say "all", "changed" or an array of route loaders to include.

Now I kinda like it actually.

@tchak
Copy link

tchak commented May 18, 2021

A possible problem with "all-but-root" is that it would need to be called in 99% of the cases when using a pattern that I described. Maybe it's ok – a complex enough app should probably abstract away forms in some own components.

@sergiodxa
Copy link
Member

I like the array of routes, with that you can have default to all and if you want something else use the array, so:

  • <Form /> <- revalidates all
  • <Form revalidate={null} /> <- revalidates all
  • <Form revalidate={[]} /> <- don't revalidate anything
  • <Form revalidate={["routes/projects/$id"]} /><- revalidate only the routes defined there

@ryanflorence
Copy link
Member Author

Remix already fetches "just the changed routes" on normal navigations, I'd like an option for that on forms, too. With only the array option you lose that and would have to manually add them.

@kentcdodds
Copy link
Member

I wonder if putting this in the form of the right place for this opt-in functionality. Wouldn't the parent loader know better whether its data needs to be reloaded? Perhaps the loader could get information about the mutation so it could determine whether to reload or not. Like, maybe it could also receive the previous value it had returned and if it decides no reload needs to happen then it could return that previous value rather than loading it again.

@ryanflorence
Copy link
Member Author

@kentcdodds HTTP is stateless so I don't know where remix would store the previous value, and GET's can't have a body to send it in the request. The form knows what data it's mutating, so I think it's a good spot.

But I'm also thinking #182 might solve this, too, if we pass it the pendingFormSubmit.

ryanflorence added a commit that referenced this issue Aug 4, 2021
- adds `useTransition` for finer grained control over pending indicators and optimistic UI
- adds "submission keys" to get the transition for a specific form's submissions rather than the global transition, allowing apps to create complex UIs with a lot of mutations happening at the same time
- adds support for concurrent form submissions (#151)
- adds route module `shouldReload` to optimize which routes should reload on form submission reloads or search param changes (#181, #175)
- reloads data when links to the current url are clicked (#128)
- provides state change updates on navigations (#54-ish)
- fixed issues with submitting a form multiple times quickly that completely broke the app before
- is mostly Remix agnostic, so we should be able to bring it over to React Router without to much headache

Closes #151, #181, #175, #128, #54, #208
@ryanflorence
Copy link
Member Author

Prerelease is out to take this for a spin:

https://docs.remix.run/0.18.0-pre.0/api/app/#shouldreload

ryanflorence added a commit that referenced this issue Aug 24, 2021
This is kinda big but opens up a lot of use cases,

## useTransition:

- can build better pending navigation UI with useTransition telling app more detailed information (state, type)
- replaces usePendingFormSubmit and usePendingLocation
- actually aborts stale submissions/loads
- fixes bugs around interrupted submissions/navigations

## useActionData

- actions can return data now
- super useful for form validation, no more screwing around with sessions

## useFetcher

- allows apps to call loaders and actions outside of navigation
- manages cancellation of stale submissions and loads
- reloads route data after actions
- commits the freshest reloaded data along the way when there are multiple inflight

## experimental_shouldReload

allows route modules to decide if they should reload or not

- after submissions
- when the search params change
- when the same href is navigated to

## other stuff

- reloads route data when the same href is navigated to
- does not create ghost history entries on interrupted navigation

## Deprecations

These old hooks still work, but have been deprecated for the new hooks.

- useRouteData -> useLoaderData
- usePendingFormSubmit -> useTransition().submission
- usePendingLocation -> useTransition().location

Closes #169, #151, #175, #128, #54, #208
ryanflorence added a commit that referenced this issue Aug 24, 2021
This is kinda big but opens up a lot of use cases,

- can build better pending navigation UI with useTransition telling app more detailed information (state, type)
- replaces usePendingFormSubmit and usePendingLocation
- actually aborts stale submissions/loads
- fixes bugs around interrupted submissions/navigations

- actions can return data now
- super useful for form validation, no more screwing around with sessions

- allows apps to call loaders and actions outside of navigation
- manages cancellation of stale submissions and loads
- reloads route data after actions
- commits the freshest reloaded data along the way when there are multiple inflight

allows route modules to decide if they should reload or not

- after submissions
- when the search params change
- when the same href is navigated to

- reloads route data when the same href is navigated to
- does not create ghost history entries on interrupted navigation

These old hooks still work, but have been deprecated for the new hooks.

- useRouteData -> useLoaderData
- usePendingFormSubmit -> useTransition().submission
- usePendingLocation -> useTransition().location

Closes #169, #151, #175, #128, #54, #208
ryanflorence added a commit that referenced this issue Aug 25, 2021
This is kinda big but opens up a lot of use cases,

- can build better pending navigation UI with useTransition telling app more detailed information (state, type)
- replaces usePendingFormSubmit and usePendingLocation
- actually aborts stale submissions/loads
- fixes bugs around interrupted submissions/navigations

- actions can return data now
- super useful for form validation, no more screwing around with sessions

- allows apps to call loaders and actions outside of navigation
- manages cancellation of stale submissions and loads
- reloads route data after actions
- commits the freshest reloaded data along the way when there are multiple inflight

allows route modules to decide if they should reload or not

- after submissions
- when the search params change
- when the same href is navigated to

- reloads route data when the same href is navigated to
- does not create ghost history entries on interrupted navigation

These old hooks still work, but have been deprecated for the new hooks.

- useRouteData -> useLoaderData
- usePendingFormSubmit -> useTransition().submission
- usePendingLocation -> useTransition().location

Closes #169, #151, #175, #128, #54, #208
ryanflorence added a commit that referenced this issue Aug 25, 2021
This is kinda big but opens up a lot of use cases,

- can build better pending navigation UI with useTransition telling app more detailed information (state, type)
- replaces usePendingFormSubmit and usePendingLocation
- actually aborts stale submissions/loads
- fixes bugs around interrupted submissions/navigations

- actions can return data now
- super useful for form validation, no more screwing around with sessions

- allows apps to call loaders and actions outside of navigation
- manages cancellation of stale submissions and loads
- reloads route data after actions
- commits the freshest reloaded data along the way when there are multiple inflight

allows route modules to decide if they should reload or not

- after submissions
- when the search params change
- when the same href is navigated to

- reloads route data when the same href is navigated to
- does not create ghost history entries on interrupted navigation

These old hooks still work, but have been deprecated for the new hooks.

- useRouteData -> useLoaderData
- usePendingFormSubmit -> useTransition().submission
- usePendingLocation -> useTransition().location

Closes #169, #151, #175, #128, #54, #208
ryanflorence added a commit that referenced this issue Aug 25, 2021
This is kinda big but opens up a lot of use cases,

- can build better pending navigation UI with useTransition telling app more detailed information (state, type)
- replaces usePendingFormSubmit and usePendingLocation
- actually aborts stale submissions/loads
- fixes bugs around interrupted submissions/navigations
- actions can return data now
- super useful for form validation, no more screwing around with sessions
- allows apps to call loaders and actions outside of navigation
- manages cancellation of stale submissions and loads
- reloads route data after actions
- commits the freshest reloaded data along the way when there are multiple inflight

allows route modules to decide if they should reload or not

- after submissions
- when the search params change
- when the same href is navigated to

other stuff

- reloads route data when the same href is navigated to
- does not create ghost history entries on interrupted navigation

These old hooks still work, but have been deprecated for the new hooks.

- useRouteData -> useLoaderData
- usePendingFormSubmit -> useTransition().submission
- usePendingLocation -> useTransition().location

Also includes a helping of docs updates

Closes #169, #151, #175, #128, #54, #208
ryanflorence added a commit that referenced this issue Aug 25, 2021
This is kinda big but opens up a lot of use cases,

- can build better pending navigation UI with useTransition telling app more detailed information (state, type)
- replaces usePendingFormSubmit and usePendingLocation
- actually aborts stale submissions/loads
- fixes bugs around interrupted submissions/navigations
- actions can return data now
- super useful for form validation, no more screwing around with sessions
- allows apps to call loaders and actions outside of navigation
- manages cancellation of stale submissions and loads
- reloads route data after actions
- commits the freshest reloaded data along the way when there are multiple inflight

allows route modules to decide if they should reload or not

- after submissions
- when the search params change
- when the same href is navigated to

other stuff

- reloads route data when the same href is navigated to
- does not create ghost history entries on interrupted navigation

These old hooks still work, but have been deprecated for the new hooks.

- useRouteData -> useLoaderData
- usePendingFormSubmit -> useTransition().submission
- usePendingLocation -> useTransition().location

Also includes a helping of docs updates

Closes #169, #151, #175, #128, #54, #208
ryanflorence added a commit that referenced this issue Aug 25, 2021
This is kinda big but opens up a lot of use cases,

- can build better pending navigation UI with useTransition telling app more detailed information (state, type)
- replaces usePendingFormSubmit and usePendingLocation
- actually aborts stale submissions/loads
- fixes bugs around interrupted submissions/navigations
- actions can return data now
- super useful for form validation, no more screwing around with sessions
- allows apps to call loaders and actions outside of navigation
- manages cancellation of stale submissions and loads
- reloads route data after actions
- commits the freshest reloaded data along the way when there are multiple inflight

allows route modules to decide if they should reload or not

- after submissions
- when the search params change
- when the same href is navigated to

other stuff

- reloads route data when the same href is navigated to
- does not create ghost history entries on interrupted navigation

These old hooks still work, but have been deprecated for the new hooks.

- useRouteData -> useLoaderData
- usePendingFormSubmit -> useTransition().submission
- usePendingLocation -> useTransition().location

Also includes a helping of docs updates

Closes #169, #151, #175, #128, #54, #208
ryanflorence added a commit that referenced this issue Aug 26, 2021
This is kinda big but opens up a lot of use cases,

- can build better pending navigation UI with useTransition telling app more detailed information (state, type)
- replaces usePendingFormSubmit and usePendingLocation
- actually aborts stale submissions/loads
- fixes bugs around interrupted submissions/navigations
- actions can return data now
- super useful for form validation, no more screwing around with sessions
- allows apps to call loaders and actions outside of navigation
- manages cancellation of stale submissions and loads
- reloads route data after actions
- commits the freshest reloaded data along the way when there are multiple inflight

allows route modules to decide if they should reload or not

- after submissions
- when the search params change
- when the same href is navigated to

other stuff

- reloads route data when the same href is navigated to
- does not create ghost history entries on interrupted navigation

These old hooks still work, but have been deprecated for the new hooks.

- useRouteData -> useLoaderData
- usePendingFormSubmit -> useTransition().submission
- usePendingLocation -> useTransition().location

Also includes a helping of docs updates

Closes #169, #151, #175, #128, #54, #208
ryanflorence added a commit that referenced this issue Sep 1, 2021
This is kinda big but opens up a lot of use cases,

- can build better pending navigation UI with useTransition telling app more detailed information (state, type)
- replaces usePendingFormSubmit and usePendingLocation
- actually aborts stale submissions/loads
- fixes bugs around interrupted submissions/navigations
- actions can return data now
- super useful for form validation, no more screwing around with sessions
- allows apps to call loaders and actions outside of navigation
- manages cancellation of stale submissions and loads
- reloads route data after actions
- commits the freshest reloaded data along the way when there are multiple inflight

allows route modules to decide if they should reload or not

- after submissions
- when the search params change
- when the same href is navigated to

other stuff

- reloads route data when the same href is navigated to
- does not create ghost history entries on interrupted navigation

These old hooks still work, but have been deprecated for the new hooks.

- useRouteData -> useLoaderData
- usePendingFormSubmit -> useTransition().submission
- usePendingLocation -> useTransition().location

Also includes a helping of docs updates

Closes #169, #151, #175, #128, #54, #208
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants