Hydrogen Mutations RFC #1773
Replies: 4 comments 11 replies
-
Have you considered type safety for the |
Beta Was this translation helpful? Give feedback.
-
We are leaning towards removing export async function api(request) {
// Render a GET request to the current URL
// Useful when the API Route handles the POST and a server component handles the GET for the same route
return new Request(request.url);
// Redirect the user to a new route
return new Request('/account');
// Most Request's should proxy the headers of the original request
return new Request('/account', { headers: request.headers });
// Data with the new request must be passed with search params
return new Request('/login?error=invaliduser');
} Pros
Cons
|
Beta Was this translation helpful? Give feedback.
-
I came to this post from another discussion. My non-expert opinion is that you seem to be reinventing the wheel here. All the problems you bring up in the original contrived example are easily solved by React-Hook-Form and React-Query, which are 2 proven libraries. Worried about user hitting submit? Reac-Hook-Form easily solves that for you. Worried about re-rendering? React-Query handles that for you easily OnSuccess=>invalidateQueries. Now admittingly, the above are client-side libraries, and I understand you are approaching this from an RSC standpoint, but I think certain things are just better handled by proven client-side libraries, especially Forms, and you can't use RSC for everything. I think you will end up basically running into the same issues that React-Hook-Form already solved, and probably create new unnecessary bugs. Why not just make things simple and use something proven? This will save alot of time, reduce bugs, and also greatly increase the visibility/value of the platform, given the sheer popularity of libraries like React-Hook-Form and React-Query. |
Beta Was this translation helpful? Give feedback.
-
I haven't looked at how you might implement this yet, but in most cases render props can be replaced with hooks. If I were coming to this framework with no context I would see render props as an old pattern and might make me turn away from hydrogen. I wish js development weren't this way, but it is 🤷 For how you could implement this. I could see a number of potential routes. Hook returns
|
Beta Was this translation helpful? Give feedback.
-
Hydrogen Mutations RFC
Last updated: June 29, 2022
Demo video: https://screenshot.click/29-13-ju7oi-exrd2.mp4
At the moment Hydrogen has mediocre support for updating information on the server. You can create an API Route and manually fetch the from the client, but there are a number of shortcomings.
Consider this contrived example where a client component submits data to an API Route:
There are a few problems with the above example:
value
is defined within a server component. At the moment the rendered value remains stale. How do we re-render that server component after the mutation? We could refresh the whole page, or come up with a server prop hack, but there is no easy performant way to do it. Either of those approaches also require at least an additional round trip to the server.The goal of this RFC is to introduce new primitives to API Routes that allow them to easily re-render server components. We also introduce an official
<Form>
component, to make interacting with API Routes easier and more performant.<Form>
componentInspired by the Remix Form, the Hydrogen
<Form>
provides a declarative way to perform mutations: creating, updating, and deleting data. Consider the above client component rewritten:Notice that we don't have to manually call
fetch
. Nor is there anonClick
handler. In fact, this entire component could be moved into the server component. That's right, no client components! Additionally, using the<Form>
component means that the<button>
still works even before the page, and JavaScript, has completely loaded and hydrated. The component automatically submits the Form by a fetch request, and falls back to a native form request when JavaScript hasn't loaded.The
<Form>
component has all of the standard props of a native<form>
element, except for the following:onSubmit
The form component takes an
onSubmit
event handler. Ifevent.preventDefault()
is called, no fetch request will be made. Also, the native event form submission won't take place.children
The children can optionally be a render prop, where we pass the form submission status. Arguments for both
loading
anderror
states:Note: Using a render prop is only available within client components, because functions as props are not serializable.
Rendering Server Components from API Routes
After a Form has been submitted, server components need to re-render to ensure that any updates to the data are reflected in the UI. Instead of returning a
new Response()
, the API route can return rendered server components withrenderRsc()
:renderRsc
takes an configuration object argument, with the following properties:pathname?: string
By default, calling
renderRsc
will re-render the server component for the current route. Optionally, you can pass thepathname
to an entirely different route. The rendered results will display in the client, and the browser will update the URL to the new route. Consider a login page, where on success, the user is redirected to an account page:Note: Data form the
<Form>
component submission is available from within the API Route by a native FormData implementation.props?: Record<string, any>
When re-rendering server components, sometimes you might want to update the server props in the server components. You can do so by passing data with
props
. This is particularly are still useful for form validation:Note: This prop data is ephemeral and just like all server props, doesn't survive a hard page refresh.
Next steps
The
<Form>
component andrenderRsc
function are implemented as outlined in this PR: Shopify/hydrogen#1552. There you can see a more realistic example of a login form and associated login API route.Long term we anticipate the
<Form>
component being used for most, if not all, mutations in Hydrogen.Questions
<Form>
submission state than a render prop?renderRsc
? Other ideas include:renderRoute
,renderPage
,getPage
. Or because it's really constructing a newRequest
object, we could make it slightly more verbose:renderRsc
altogether and instead just have the API route return anew Request()
:renderRsc
from rendering a sub-tree.Beta Was this translation helpful? Give feedback.
All reactions