Unexpected behaviour when redirecting in action
See original GitHub issueWhat version of Remix are you using?
1.4.1
Steps to Reproduce
Create a Remix project (with the built in Remix server) with the following routes:
index.tsx:
import { memo } from 'react'
const IndexRoute = memo(() => {
return <h1>Home</h1>
})
IndexRoute.displayName = 'IndexRoute'
export default IndexRoute
magic-link.tsx:
import { memo, useEffect } from 'react'
import { LoaderFunction, json, useLoaderData, useSubmit } from 'remix'
import { emailFormFieldName, codeFormFieldName } from '~/routes/verify-magic-link'
type LoaderData = {
email: string,
code: string
}
const loader: LoaderFunction = async ({ request }) => {
const url = new URL(request.url)
const email = url.searchParams.get("email") ?? ''
const code = url.searchParams.get("code") ?? ''
return json<LoaderData>({
email,
code
})
}
const MagicLinkRoute = memo(() => {
const loaderData = useLoaderData<LoaderData>()
const submit = useSubmit()
useEffect(() => {
const formData = new FormData()
formData.append(emailFormFieldName, loaderData.email)
formData.append(codeFormFieldName, loaderData.code)
submit(formData, { method: 'post', action: '/verify-magic-link' })
}, [loaderData.email, loaderData.code, submit])
return (
<p>Some pending UI</p>
)
})
MagicLinkRoute.displayName = 'MagicLinkRoute'
export default MagicLinkRoute
export { loader }
verify-magic-link.tsx:
import { memo } from 'react'
import { ActionFunction, json, redirect, useActionData } from 'remix'
export const emailFormFieldName = 'email'
export const codeFormFieldName = 'code'
// fake verifyMagicLink function with forced failure
const verifyMagicLink = ({ email, code } : { email: string, code: string }) => Promise.resolve(false)
type ActionData = Awaited<ReturnType<typeof verifyMagicLink>>
const action: ActionFunction = async ({ request }) => {
const body = await request.formData()
const email = body.get(emailFormFieldName)?.toString() ?? ''
const code = body.get(codeFormFieldName)?.toString() ?? ''
const verifyMagicLinkResult = await verifyMagicLink({ email, code })
if (verifyMagicLinkResult === true) {
return redirect('/')
}
return json<ActionData>(verifyMagicLinkResult)
}
const VerifyMagicLinkRoute = memo(() => {
const actionData = useActionData<ActionData>()
return (
<p>{JSON.stringify(actionData, null, 2)}</p>
)
})
VerifyMagicLinkRoute.displayName = 'VerifyMagicLinkRoute'
export default VerifyMagicLinkRoute
export { action }
In the entry.server.tsx
handleRequest
function put the following just before returning the response:
console.log({
type: 'handleRequest',
url: request.url,
method: request.method,
response: newResponse.status
})
In the entry.server.tsx
handleDataRequest
function put the following just before returning the response:
console.log({
type: 'handleDataRequest',
url: request.url,
method: request.method,
response: newResponse.status
})
Go to https://localhost:3000/magic-link?code=123456&email=test@test.com
in your browser. In the terminal you should see:
{
type: 'handleRequest',
url: 'http://localhost:3000/magic-link?code=123456&email=test@test.com',
method: 'GET',
response: 200
}
{
type: 'handleDataRequest',
url: 'http://localhost:3000/verify-magic-link?_data=routes%2Fverify-magic-link',
method: 'POST',
response: 200
}
{
type: 'handleDataRequest',
url: 'http://localhost:3000/verify-magic-link?_data=root',
method: 'GET',
response: 200
}
This is what I would expect to see.
Now in verify-magic-link.tsx
change const verifyMagicLink = ({ email, code } : { email: string, code: string }) => Promise.resolve(false)
to const verifyMagicLink = ({ email, code } : { email: string, code: string }) => Promise.resolve(true)
.
Run the same request in your browser again.
Expected Behavior
Terminal should show:
{
type: 'handleRequest',
url: 'http://localhost:3000/magic-link?code=123456&email=test@test.com',
method: 'GET',
response: 200
}
{
type: 'handleDataRequest',
url: 'http://localhost:3000/verify-magic-link?_data=routes%2Fverify-magic-link',
method: 'POST',
response: 302
}
{
type: 'handleDataRequest',
url: 'http://localhost:3000/?_data=root',
method: 'GET',
response: 200
}
Actual Behavior
Terminal shows:
{
type: 'handleRequest',
url: 'http://localhost:3000/magic-link?code=123456&email=test@test.com',
method: 'GET',
response: 200
}
{
type: 'handleDataRequest',
url: 'http://localhost:3000/?_data=root',
method: 'GET',
response: 200
}
The POST
request does not get logged by either handleRequest
or handleDataRequest
.
Even though I am taken to the index.tsx
route as expected the 302
redirect response never seems to be returned to the browser. Instead when I look in the browser network tab I can see that the the response to the POST
request was a 204 response.
This is causing me issues because I would like to add a set-cookie
header on the redirect response but the cookie never gets set because the redirect response doesn’t make it to the browser.
Issue Analytics
- State:
- Created a year ago
- Comments:15
@fknop I had the same issue - lots of weird things happening with
LiveReload
andremix-auth
, especially re: redirecting when trying to log in. I verified that using the old version ofLiveReload
stops this problem from happening. Here’s the “custom”LiveReload
function I’m using instead of the production one from remix (which is just the1.6.4
version with no other changes):I believe PR 4725 fixes this issue.