-
Notifications
You must be signed in to change notification settings - Fork 323
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 Hydrogen Form component for easier mutations #1070
Conversation
I'm pretty sure to handle forms properly, this will need Shopify/hydrogen#1067 I'll test with and without node 16 and undici. If it works, I'll change the upstream branch to be v1.x. |
method, | ||
headers: { | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
'Hydrogen-Client': 'Form-Action', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unsure about this header name
if (!Array.from((apiResponse.headers as any).keys()).length) { | ||
request.headers.forEach((value, key) => { | ||
apiResponse.headers.set(key, value); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the dev doesn't explicitly define headers, then use the headers on the original request.
`?state=${encodeURIComponent( | ||
JSON.stringify({ | ||
pathname: newUrl.pathname, | ||
search: '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably should put the search parameters on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thin it's better with the search
as empty string, yes. Recently we had issues with prefetching because of this (#1059).
Or do you mean passing search parameters from newUrl
?
headers, | ||
headers: { | ||
'X-Shopify-Storefront-Access-Token': storefrontToken, | ||
'Accept-Language': (locale as string) ?? defaultLocale, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should no longer use this header. Sorry I should had remove this as part of Shopify/hydrogen#1028
@@ -0,0 +1,57 @@ | |||
import React, {useCallback, useRef} from 'react'; | |||
// @ts-ignore | |||
import {createFromFetch} from '@shopify/hydrogen/vendor/react-server-dom-vite'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice trick!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, perhaps we could re-export this from rsc.ts
to centralize where we use the vendor dir?
<Form action="/form" method="POST"> | ||
<b>Count: {count}</b> | ||
<button type="submit">Increment</button> | ||
</Form> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you show an example on how to response to the submitted form?
ie. show different alert message base on if the submission is success or failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michenly updated
useEffect(() => { | ||
setApiResponse(null); | ||
}, [serverState]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will clear the API response if we continue navigating by changing serverState, right?
Maybe we could add some comments around this area for those who are not very familiar with RSC.
setServerState={setServerState} | ||
setApiResponse={setApiResponse} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will we need a more generic setResponse
at some point? Or do we think we only want to "overwrite" server state with responses from API? 🤔
// JavaScript is disabled on the client, handle the response without streaming | ||
return handleRequest(apiResponse, { | ||
...options, | ||
streamableResponse: undefined, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, but wouldn't this also disable streaming for raw HTML forms? I guess it's a minor drawback.
Also, I don't think streamableResponse: undefined
works in Node. Currently we are writing to this response in the Node branch. We would need a new parameter like doStream: boolean
or anything like that.
Edit: it actually works but only when using our custom hydrogenMiddleware
. Our current render
function is kind of weird, it always returns a Response
even in Node, so it needs to be transformed later to response.write
🙈 -- perhaps we should always do this once we only support Node 16+...
return apiResponse instanceof Request | ||
? handleRequest(apiResponse, options) | ||
: apiResponse; | ||
if (apiResponse instanceof Request) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move most of this logic to renderApiRoute
itself? If await route.resource
returns a Request
, we can set headers and change RSC url within renderApiRoute
. Or move it to a different function if you prefer but at least make the logic in the handleRequest
a bit easier to scan 🤔
e015f1e
to
9832f3a
Compare
d02aab9
to
a6a4966
Compare
Experimental
<Form>
component for easier mutations. Example usage: