mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
a8404107f2
Fixes #70216 ### What? The `redirect` function from `next/navigation` does not honor the redirect type when used in server actions. When setting `type` to `replace`, the server action pushes to history instead of replacing the route. This stems from https://github.com/vercel/next.js/pull/54458 ### Why? The server action should honor the redirect type. ### How? By setting `x-action-redirect` header to `<url>;<redirectType>`, we extract the type of redirect to be performed on the client. This is handled in a way that if the type is absent, we fallback to `push`. Demo: https://github.com/user-attachments/assets/3c84c6e3-2b08-4df3-89b2-5f9d290cc5ff Observe that once the form is submitted and the action replaced the URL with `/`, we didn't go back to the `/child` route. --------- Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
100 lines
2.3 KiB
JavaScript
100 lines
2.3 KiB
JavaScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
|
|
export default function UI({
|
|
getCookie,
|
|
getHeader,
|
|
setCookie,
|
|
setCookieAndRedirect,
|
|
getAuthedUppercase,
|
|
}) {
|
|
const [result, setResult] = useState('')
|
|
|
|
return (
|
|
<div>
|
|
<h1>{result}</h1>
|
|
<button
|
|
id="cookie"
|
|
onClick={async () => {
|
|
// set cookie
|
|
const random = Math.random()
|
|
document.cookie = `random=${random}`
|
|
const res = await getCookie('random')
|
|
setResult(random + ':' + res.value)
|
|
}}
|
|
>
|
|
getCookie
|
|
</button>
|
|
<button
|
|
id="setCookie"
|
|
onClick={async () => {
|
|
// set cookie on server side
|
|
const random = Math.random()
|
|
const res = await setCookie('random-server', random)
|
|
setResult(
|
|
random +
|
|
':' +
|
|
res.value +
|
|
':' +
|
|
document.cookie.match(/random-server=([^;]+)/)?.[1]
|
|
)
|
|
}}
|
|
>
|
|
setCookie
|
|
</button>
|
|
<button
|
|
id="header"
|
|
onClick={async () => {
|
|
const res = await getHeader('User-Agent')
|
|
setResult(res)
|
|
}}
|
|
>
|
|
getHeader
|
|
</button>
|
|
<button
|
|
id="authed"
|
|
onClick={async () => {
|
|
try {
|
|
const res = await getAuthedUppercase('hello, world')
|
|
setResult(res)
|
|
} catch (err) {
|
|
setResult('Error: ' + err.message)
|
|
}
|
|
}}
|
|
>
|
|
getAuthedUppercase
|
|
</button>
|
|
<form>
|
|
<button
|
|
id="setCookieAndRedirect"
|
|
formAction={async () => {
|
|
await setCookieAndRedirect(
|
|
'redirect',
|
|
Math.random().toString(36).substring(7),
|
|
'/redirect-target'
|
|
)
|
|
}}
|
|
>
|
|
setCookieAndRedirect
|
|
</button>
|
|
</form>
|
|
<form>
|
|
<button
|
|
id="setCookieAndRedirectReplace"
|
|
formAction={async () => {
|
|
await setCookieAndRedirect(
|
|
'redirect',
|
|
Math.random().toString(36).substring(7),
|
|
'/redirect-target',
|
|
'replace'
|
|
)
|
|
}}
|
|
>
|
|
setCookieAndRedirectReplace
|
|
</button>
|
|
</form>
|
|
</div>
|
|
)
|
|
}
|