You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -624,54 +624,6 @@ You can prevent sensitive data (such as passwords and credit card numbers) from
624
624
625
625
In this example, if the data does not validate, only the first `<input>` will be populated when the page reloads.
626
626
627
-
### Single-flight mutations
628
-
629
-
By default, all queries used on the page (along with any `load` functions) are automatically refreshed following a successful form submission. This ensures that everything is up-to-date, but it's also inefficient: many queries will be unchanged, and it requires a second trip to the server to get the updated data.
630
-
631
-
Instead, we can specify which queries should be refreshed in response to a particular form submission. This is called a _single-flight mutation_, and there are two ways to achieve it. The first is to refresh the query on the server, inside the form handler:
The second is to drive the single-flight mutation from the client, which we'll see in the section on [`enhance`](#form-enhance).
674
-
675
627
### Returns and redirects
676
628
677
629
The example above uses [`redirect(...)`](@sveltejs-kit#redirect), which sends the user to the newly created page. Alternatively, the callback could return data, in which case it would be available as `createPost.result`:
@@ -769,39 +721,6 @@ We can customize what happens when the form is submitted with the `enhance` meth
769
721
770
722
The callback receives the `form` element, the `data` it contains, and a `submit` function.
771
723
772
-
To enable client-driven [single-flight mutations](#form-Single-flight-mutations), use `submit().updates(...)`. For example, if the `getPosts()` query was used on this page, we could refresh it like so:
The override will be applied immediately, and released when the submission completes (or fails).
804
-
805
724
### Multiple instances of a form
806
725
807
726
Some forms may be repeated as part of a list. In this case you can create separate instances of a form function via `for(id)` to achieve isolation.
@@ -943,78 +862,126 @@ Now simply call `addLike`, from (for example) an event handler:
943
862
944
863
> [!NOTE] Commands cannot be called during render.
945
864
946
-
### Updating queries
865
+
## Single-flight mutations
866
+
867
+
The purpose of both [`form`](#form) and [`command`](#command) is *mutating data*. In many cases, mutating data invalidates other data. By default, `form` deals with this by automatically invalidating all queries and load functions following a successful submission, to emulate what would happen with a traditional full-page reload. `command`, on the other hand, does nothing. Typically, neither of these options is going to be the ideal solution — invalidating everything is likely wasteful, as it's unlikely a form submission changed *everything* being displayed on your webpage. In the case of `command`, doing nothing likely *under*-invalidates your app, leaving stale data displayed. In both cases, it's common to have to perform two round-trips to the server: One to run the mutation, and another after that completes to re-request the data from any queries you need to refresh.
947
868
948
-
To update `getLikes(item.id)`, or any other query, we need to tell SvelteKit _which_ queries need to be refreshed (unlike `form`, which by default invalidates everything, to approximate the behaviour of a native form submission).
869
+
SvelteKit solves both of these problems with *single-flight mutations*: Your `form` submission or `command` invocation can refresh queries and pass their results back to the client in a single request.
949
870
950
-
We either do that inside the command itself...
871
+
### Server-driven refreshes
872
+
873
+
In most circumstances, the server handler knows what client data needs to be updated based on its arguments:
// Just like within form functions you can also do
975
-
// getLikes(id).set(...)
976
-
// in case you have the result already
977
-
});
888
+
exportconstcreatePost=form(
889
+
v.object({/* ... */}),
890
+
async (data) => {
891
+
// form logic goes here...
892
+
893
+
// Refresh `getPosts()` on the server, and send
894
+
// the data back with the result of `createPost`
895
+
// it's safe to throw away the promise from `refresh`,
896
+
// as the framework awaits it for us before serving the response
897
+
+++voidgetPosts().refresh();+++
898
+
899
+
// Redirect to the newly created page
900
+
redirect(303, `/blog/${slug}`);
901
+
}
902
+
);
903
+
904
+
exportconstupdatePost=form(
905
+
v.object({ id:v.string() }),
906
+
async (post) => {
907
+
// form logic goes here...
908
+
constresult=externalApi.update(post);
909
+
910
+
// The API already gives us the updated post,
911
+
// no need to refresh it, we can set it directly
912
+
+++getPost(post.id).set(result);+++
913
+
}
914
+
);
978
915
```
979
916
980
-
...or when we call it:
917
+
Because queries are keyed based on their arguments, `awaitgetPost(post.id).set(result)` on the server knows to look up the matching `getPost(id)` on the client to update it. The same goes for `getPosts().refresh()` -- it knows to look up `getPosts()` with no argument on the client.
Unfortunately, life isn't always as simple as the preceding example. The server always knows which query _functions_ to update, but it may not know which specific query _instances_ to update. For example, if `getPosts({ filter:'author:santa' })` is rendered on the client, calling `getPosts().refresh()` in the server handler won't update it. You'd need to call `getPosts({ filter:'author:santa' }).refresh()` instead — but how could you know which specific combinations of filters are currently rendered on the client, especially if your query argument is more complicated than an object with just one key?
SvelteKit makes this easy by allowing the client to _request_ that the server updates specific data using `submit().updates` (for `form`) or `myCommand().updates` (for `command`):
`requested` gives you access to the requested query arguments for the supplied query. It returns the *parsed* arguments for the query -- when these arguments are passed back into the query in `getPosts(arg).refresh()`, they will not be parsed again. If parsing an argument fails, that query will error, but the entire command will not fail. `requested`'s second parameter, `limit`, is the maximum number of items it will return. Any refresh requests beyond this limit will fail.
975
+
976
+
Additionally, `requested` allows a simple shorthand when all you want to do is refresh the requested query instances:
@@ -2654,7 +2650,7 @@ type RemoteQuery<T> = RemoteResource<T> & {
2654
2650
*/
2655
2651
refresh(): Promise<void>;
2656
2652
/**
2657
-
* Temporarily override the value of a query. This is used with the `updates` method of a [command](https://svelte.dev/docs/kit/remote-functions#command-Updating-queries) or [enhanced form submission](https://svelte.dev/docs/kit/remote-functions#form-enhance) to provide optimistic updates.
2653
+
* Temporarily override a query's value during a [single-flight mutation](https://svelte.dev/docs/kit/remote-functions#Single-flight-mutations) to provide optimistic updates.
2658
2654
*
2659
2655
* ```svelte
2660
2656
* <script>
@@ -2699,26 +2695,23 @@ type RemoteQueryFunction<Input, Output> = (
2699
2695
<divclass="ts-block">
2700
2696
2701
2697
```dts
2702
-
interface RemoteQueryOverride {/*…*/}
2698
+
type RemoteQueryOverride = () => void;
2703
2699
```
2704
2700
2705
-
<divclass="ts-block-property">
2706
-
2707
-
```dts
2708
-
_key: string;
2709
-
```
2710
-
2711
-
<divclass="ts-block-property-details"></div>
2712
2701
</div>
2713
2702
2714
-
<divclass="ts-block-property">
2703
+
## RemoteQueryUpdate
2704
+
2705
+
<divclass="ts-block">
2715
2706
2716
2707
```dts
2717
-
release(): void;
2708
+
type RemoteQueryUpdate =
2709
+
| RemoteQuery<any>
2710
+
| RemoteQueryFunction<any, any>
2711
+
| RemoteQueryOverride;
2718
2712
```
2719
2713
2720
-
<divclass="ts-block-property-details"></div>
2721
-
</div></div>
2714
+
</div>
2722
2715
2723
2716
## RemoteResource
2724
2717
@@ -3046,6 +3039,30 @@ type RequestHandler<
3046
3039
3047
3040
</div>
3048
3041
3042
+
## RequestedResult
3043
+
3044
+
<divclass="ts-block">
3045
+
3046
+
```dts
3047
+
type RequestedResult<T> = Iterable<T> &
3048
+
AsyncIterable<T> & {
3049
+
/**
3050
+
* Call `refresh` on all queries selected by this `requested` invocation.
0 commit comments